2101 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			2101 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| \input texinfo        @c                    -*- Texinfo -*-
 | |
| @setfilename porting.info
 | |
| @settitle Embed with GNU
 | |
| 
 | |
| @c
 | |
| @c This file documents the process of porting the GNU tools to an
 | |
| @c embedded environment.
 | |
| @c
 | |
| 
 | |
| @finalout
 | |
| @setchapternewpage off
 | |
| @iftex
 | |
| @raggedbottom
 | |
| @global@parindent=0pt
 | |
| @end iftex
 | |
| 
 | |
| @titlepage
 | |
| @title Embed With GNU
 | |
| @subtitle Porting The GNU Tools To Embedded Systems
 | |
| @sp 4
 | |
| @subtitle Spring 1995
 | |
| @subtitle Very *Rough* Draft
 | |
| @author Rob Savoye - Cygnus Support
 | |
| @page
 | |
| 
 | |
| @vskip 0pt plus 1filll
 | |
| Copyright @copyright{} 1993, 1994, 1995 Cygnus Support
 | |
| 
 | |
| Permission is granted to make and distribute verbatim copies of
 | |
| this manual provided the copyright notice and this permission notice
 | |
| are preserved on all copies.
 | |
| 
 | |
| Permission is granted to copy and distribute modified versions of this
 | |
| manual under the conditions for verbatim copying, provided also that
 | |
| the entire resulting derived work is distributed under the terms of a
 | |
| permission notice identical to this one.
 | |
| 
 | |
| Permission is granted to copy and distribute translations of this manual
 | |
| into another language, under the above conditions for modified versions.
 | |
| @end titlepage
 | |
| 
 | |
| @ifinfo
 | |
| @format
 | |
| START-INFO-DIR-ENTRY
 | |
| * Embed with GNU: (porting-).         Embed with GNU
 | |
| END-INFO-DIR-ENTRY
 | |
| @end format
 | |
| Copyright (c) 1993, 1994, 1995 Cygnus Support
 | |
| 
 | |
| Permission is granted to make and distribute verbatim copies of
 | |
| this manual provided the copyright notice and this permission notice
 | |
| are preserved on all copies.
 | |
| 
 | |
| Permission is granted to copy and distribute modified versions of this
 | |
| manual under the conditions for verbatim copying, provided also that
 | |
| the entire resulting derived work is distributed under the terms of a
 | |
| permission notice identical to this one.
 | |
| 
 | |
| Permission is granted to copy and distribute translations of this manual
 | |
| into another language, under the above conditions for modified versions.
 | |
| 
 | |
| @node Top
 | |
| @top Embed with GNU
 | |
| 
 | |
| @end ifinfo
 | |
| @strong{Rough Draft}
 | |
| 
 | |
| The goal of this document is to gather all the information needed to
 | |
| port the GNU tools to a new embedded target in one place. This will
 | |
| duplicate some info found in the other manual for the GNU tools, but
 | |
| this should be all you'll need. 
 | |
| 
 | |
| @menu
 | |
| * Libgloss::            Libgloss, a library of board support packages.
 | |
| * GCC::                 Porting GCC/G++ to a new embedded target.
 | |
| * Libraries::           Making Newlib run on an new embedded target.
 | |
| * GDB::                 Making GDB understand a new back end.
 | |
| * Binutils::            Using the GNU binary utilities.
 | |
| * Code Listings::       Listings of the commented source code from the
 | |
|                         text.
 | |
| @end menu
 | |
| 
 | |
| @node Libgloss, GCC, Top, Top
 | |
| @chapter Libgloss
 | |
| Libgloss is a library for all the details that usually get glossed over.
 | |
| This library refers to things like startup code, and usually I/O support
 | |
| for @code{gcc} and @code{C library}. The C library used through out
 | |
| this manual is @code{newlib}. Newlib is a ANSI conforming C library
 | |
| developed by Cygnus Support. Libgloss could easily be made to
 | |
| support other C libraries, and it can be used standalone as well. The
 | |
| standalone configuration is typically used when bringing up new
 | |
| hardware, or on small systems. 
 | |
| 
 | |
| For a long time, these details were part of newlib. This approach worked
 | |
| well when a complete tool chain only had to support one system. A tool
 | |
| chain refers to the series of compiler passes required to produce a
 | |
| binary file that will run on an embedded system. For C, the passes are
 | |
| cpp, gcc, gas, ld. Cpp is the preprocessor, which process all the header
 | |
| files and macros. Gcc is the compiler, which produces assembler from the
 | |
| processed C files. Gas assembles the code into object files, and then ld
 | |
| combines the object files and binds the code to addresses and produces
 | |
| the final executable image. 
 | |
| 
 | |
| Most of the time a tool chain does only have to support one target
 | |
| execution environment. An example of this would be a tool chain for the
 | |
| AMD 29k processor family. All of the execution environments for this
 | |
| processor are have the same interface, the same memory map, and the same
 | |
| I/O code. In this case all of the support code is in newlib/sys/FIXME.
 | |
| Libgloss's creation was forced initially be the @code{cpu32} processor
 | |
| family. There are many different execution environments for this line,
 | |
| and they vary wildly. newlib itself has only has a few dependencies that
 | |
| it needs for each target. These are explained later in this doc. The
 | |
| hardware dependent part of newlib was reorganized into a separate
 | |
| directory structure within newlib called the stub dirs. It was initially
 | |
| called this because most of the routines newlib needs for a target were
 | |
| simple stubs that do nothing, but return a value to the application. They
 | |
| only exist so the linker can produce a final executable image. This work
 | |
| was done during the early part of 1993.
 | |
| 
 | |
| After a while it became apparent that this approach of isolating the
 | |
| hardware and systems files together made sense. Around this same time
 | |
| the stub dirs were made to run standalone, mostly so it could also be
 | |
| used to support GDB's remote debugging needs. At this time it was
 | |
| decided to move the stub dirs out of newlib and into it's own separate
 | |
| library so it could be used standalone, and be included in various other
 | |
| GNU tools without having to bring in all of newlib, which is large. The
 | |
| new library is called Libgloss, for Gnu Low-level OS support. 
 | |
| 
 | |
| @menu
 | |
| * Supported targets::           What targets libgloss currently
 | |
|                                 supports.
 | |
| * Building libgloss::           How to configure and built libgloss
 | |
|                                 for a target.
 | |
| * Board support::               How to add support for a new board.
 | |
| @end menu
 | |
| 
 | |
| @node Supported targets, Building libgloss, Libgloss, Libgloss
 | |
| @section Supported Targets
 | |
| Currently libgloss is being used for the following targets:
 | |
| 
 | |
| @menu
 | |
| * Sparclite::                   Fujitsu's sparclite.
 | |
| * CPU32::                       Various m68k based targets.
 | |
| * Mips::                        Mips code based targets.
 | |
| * PA-RISC::                     Precision Risc Organization..
 | |
| @end menu
 | |
| 
 | |
| @node Sparclite, CPU32, , Supported targets
 | |
| @subsection Sparclite Targets Supported
 | |
| @c FIXME: put links to the docs in etc/targetdoc
 | |
| This is for the Fujitsu Sparclite family of processors. Currently this 
 | |
| covers the ex930, ex931, ex932, ex933, and the ex934. In addition to the
 | |
| I/O code a startup file, this has a GDB debug-stub that gets linked into
 | |
| your application. This is an exception handler style debug stub. For
 | |
| more info, see the section on Porting GDB. @ref{GDB,,Porting GDB}.
 | |
| 
 | |
| The Fujitsu eval boards use a host based terminal program to load and
 | |
| execute programs on the target. This program, @code{pciuh} is relatively
 | |
| new (in 1994) and it replaced the previous ROM monitor which had the
 | |
| shell in the ROM. GDB uses the the GDB remote protocol, the relevant
 | |
| source files from the gdb sources are remote-sparcl.c. The debug stub is
 | |
| part of libgloss and is called sparcl-stub.c.
 | |
| 
 | |
| @node CPU32, Mips, Sparclite, Supported targets
 | |
| @subsection Motorola CPU32 Targets supported
 | |
| This refers to Motorola's m68k based CPU32 processor family. The crt0.S
 | |
| startup file should be usable with any target environment, and it's
 | |
| mostly just the I/O code and linker scripts that vary. Currently there
 | |
| is support for the Motorola MVME line of 6U VME boards and IDP
 | |
| line of eval boards. All of the
 | |
| Motorola VME boards run @code{Bug}, a ROM based debug monitor.
 | |
| This monitor has the feature of using user level traps to do I/O, so
 | |
| this code should be portable to other MVME boards with little if any
 | |
| change. The startup file also can remain unchanged. About the only thing
 | |
| that varies is the address for where the text section begins. This can
 | |
| be accomplished either in the linker script, or on the command line
 | |
| using the @samp{-Ttext [address]}.
 | |
| 
 | |
| @c FIXME: Intermetrics or ISI wrote rom68k ?
 | |
| There is also support for the @code{rom68k} monitor as shipped on
 | |
| Motorola's IDP eval board line. This code should be portable across the
 | |
| range of CPU's the board supports. There is also GDB support for this
 | |
| target environment in the GDB source tree. The relevant files are
 | |
| gdb/monitor.c, monitor.h, and rom58k-rom.c. The usage of these files is
 | |
| discussed in the GDB section.
 | |
| 
 | |
| @node Mips, PA-RISC, CPU32, Supported targets
 | |
| @subsection Mips core Targets Supported
 | |
| The Crt0 startup file should run on any mips target that doesn't require
 | |
| additional hardware initialization. The I/O code so far only supports a
 | |
| custom LSI33k based RAID disk controller board. It should easy to
 | |
| change to support the IDT line of eval boards. Currently the two
 | |
| debugging protocols supported by GDB for mips targets is IDT's mips
 | |
| debug protocol, and a customized hybrid of the standard GDB remote
 | |
| protocol and GDB's standard ROM monitor support. Included here is the
 | |
| debug stub for the hybrid monitor. This supports the LSI33k processor,
 | |
| and only has support for the GDB protocol commands @code{g}, @code{G},
 | |
| @code{m}, @code{M}, which basically only supports the register and
 | |
| memory reading and writing commands. This is part of libgloss and is
 | |
| called lsi33k-stub.c.
 | |
| 
 | |
| The crt0.S should also work on the IDT line of eval boards, but has only
 | |
| been run on the LSI33k for now. There is no I/O support for the IDT eval
 | |
| board at this time. The current I/O code is for a customized version of
 | |
| LSI's @code{pmon} ROM monitor. This uses entry points into the monitor,
 | |
| and should easily port to other versions of the pmon monitor. Pmon is
 | |
| distributed in source by LSI.
 | |
| 
 | |
| @node PA-RISC, , Mips, Supported targets
 | |
| @subsection PA-RISC Targets Supported
 | |
| This supports the various boards manufactured by the HP-PRO consortium.
 | |
| This is a group of companies all making variations on the PA-RISC
 | |
| processor. Currently supported are ports to the WinBond @samp{Cougar}
 | |
| board based around their w89k version of the PA. Also supported is the
 | |
| Oki op50n processor.
 | |
| 
 | |
| There is also included, but never built an unfinished port to the HP 743
 | |
| board. This board is the main CPU board for the HP700 line of industrial
 | |
| computers. This target isn't exactly an embedded system, in fact it's
 | |
| really only designed to load and run HP-UX. Still, the crt0.S and I/O
 | |
| code are fully working. It is included mostly because their is a barely
 | |
| functioning exception handler GDB debug stub, and I hope somebody could
 | |
| use it. The other PRO targets all use GDB's ability to talk to ROM
 | |
| monitors directly, so it doesn't need a debug stub. There is also a
 | |
| utility that will produce a bootable file by HP's ROM monitor. This is
 | |
| all included in the hopes somebody else will finish it. :-)
 | |
| 
 | |
| Both the WinBond board and the Oki board download srecords. The WinBond
 | |
| board also has support for loading the SOM files as produced by the
 | |
| native compiler on HP-UX. WinBond supplies a set of DOS programs that
 | |
| will allow the loading of files via a bidirectional parallel port. This
 | |
| has never been tested with the output of GNU SOM, as this manual is
 | |
| mostly for Unix based systems. 
 | |
| 
 | |
| @node Building libgloss, Board support, Supported targets, Libgloss
 | |
| @section Configuring and building libgloss.
 | |
| 
 | |
| Libgloss uses an autoconf based script to configure. Autoconf scripts
 | |
| are portable shell scripts that are generated from a configure.in file.
 | |
| Configure input scripts are based themselves on m4. Most configure
 | |
| scripts run a series of tests to determine features the various
 | |
| supported features of the target. For features that can't be determined
 | |
| by a feature test, a makefile fragment is merged in. The configure
 | |
| process leaves creates a Makefile in the build directory. For libgloss,
 | |
| there are only a few configure options of importance. These are --target
 | |
| and --srcdir. 
 | |
| 
 | |
| Typically libgloss is built in a separate tree just for objects. In this
 | |
| manner, it's possible to have a single source tree, and multiple object
 | |
| trees. If you only need to configure for a single target environment,
 | |
| then you can configure in the source tree. The argument for --target is
 | |
| a config string. It's usually safest to use the full canonical opposed
 | |
| to the target alias. So, to configure for a CPU32 (m68k) with a separate
 | |
| source tree, use:
 | |
| 
 | |
| @smallexample
 | |
| ../src/libgloss/configure --verbose --target m68k-coff
 | |
| @end smallexample
 | |
| 
 | |
| The configure script is in the source tree. When configure is invoked
 | |
| it will determine it's own source tree, so the --srcdir is would be
 | |
| redundant here.
 | |
| 
 | |
| Once libgloss is configured, @code{make} is sufficient to build it. The
 | |
| default values for @code{Makefiles} are typically correct for all
 | |
| supported systems. The test cases in the testsuite will also built
 | |
| automatically as opposed to a @code{make check}, where test binaries
 | |
| aren't built till test time. This is mostly cause the libgloss
 | |
| testsuites are the last thing built when building the entire GNU source
 | |
| tree, so it's a good test of all the other compilation passes.
 | |
| 
 | |
| The default values for the Makefiles are set in the Makefile fragment
 | |
| merged in during configuration. This fragment typically has rules like
 | |
| 
 | |
| @smallexample
 | |
| CC_FOR_TARGET = `if [ -f $$@{OBJROOT@}/gcc/xgcc ] ; \
 | |
| 	then echo $@{OBJROOT@}/gcc/xgcc -B$@{OBJROOT@}/gcc/ ; \
 | |
| 	else t='$@{program_transform_name@}'; echo gcc | sed -e '' $$t ; fi`
 | |
| @end smallexample
 | |
| 
 | |
| Basically this is a runtime test to determine whether there are freshly
 | |
| built executables for the other main passes of the GNU tools. If there
 | |
| isn't an executable built in the same object tree, then
 | |
| @emph{transformed}the generic tool name (like gcc) is transformed to the
 | |
| name typically used in GNU cross compilers. The  names are
 | |
| typically based on the target's canonical name, so if you've configured
 | |
| for @code{m68k-coff} the transformed name is @code{m68k-coff-gcc} in
 | |
| this case. If you install with aliases or rename the tools, this won't
 | |
| work, and it will always look for tools in the path. You can force the a
 | |
| different name to work by reconfiguring with the
 | |
| @code{--program-transform-name} option to configure. This option takes a
 | |
| sed script like this @code{-e s,^,m68k-coff-,} which produces tools
 | |
| using the standard names (at least here at Cygnus). 
 | |
| 
 | |
| The search for the other GNU development tools is exactly the same idea. 
 | |
| This technique gets messier when build options like @code{-msoft-float}
 | |
| support are used. The Makefile fragments set the @code{MUTILIB}
 | |
| variable, and if it is set, the search path is modified. If the linking
 | |
| is done with an installed cross compiler, then none of this needs to be
 | |
| used. This is done so libgloss will build automatically with a fresh,
 | |
| and uninstalled object tree. It also makes it easier to debug the other
 | |
| tools using libgloss's test suites.
 | |
| 
 | |
| @node Board support, , Building libgloss, Libgloss
 | |
| @section Adding Support for a New Board
 | |
| 
 | |
| This section explains how to add support for a new board to libgloss.
 | |
| In order to add support for a board, you must already have developed a
 | |
| toolchain for the target architecture.
 | |
| 
 | |
| All of the changes you will make will be in the subdirectory named
 | |
| after the architecture used by your board.  For example, if you are
 | |
| developing support for a new ColdFire board, you will modify files in
 | |
| the @file{m68k} subdirectory, as that subdirectory contains support
 | |
| for all 68K devices, including architecture variants like ColdFire.
 | |
| 
 | |
| In general, you will be adding three components: a @file{crt0.S} file
 | |
| (@pxref{Crt0}), a linker script (@pxref{Linker Scripts}), and a
 | |
| hardware support library.  Each should be prefixed with the name of
 | |
| your board.  For example, if you ard adding support for a new Surf
 | |
| board, then you will be adding the assembly @file{surf-crt0.S} (which
 | |
| will be assembled into @file{surf-crt0.o}), the linker script
 | |
| @file{surf.ld}, and other C and assembly files which will be combined
 | |
| into the hardware support library @file{libsurf.a}.
 | |
| 
 | |
| You should modify @file{Makefile.in} to define new variables
 | |
| corresponding to your board.  Although there is some variation between
 | |
| architectures, the general convention is to use the following format:
 | |
| 
 | |
| @example
 | |
| # The name of the crt0.o file.
 | |
| SURF_CRT0    = surf-crt0.o
 | |
| # The name of the linker script.
 | |
| SURF_SCRIPTS = surf.ld
 | |
| # The name of the hardware support library.
 | |
| SURF_BSP     = libsurf.a
 | |
| # The object files that make up the hardware support library.
 | |
| SURF_OBJS    = surf-file1.o surf-file2.o 
 | |
| # The name of the Makefile target to use for installation.
 | |
| SURF_INSTALL = install-surf
 | |
| @end example
 | |
| 
 | |
| Then, you should create the @code{$@{SURF_BSP@}} and
 | |
| @code{$@{SURF_INSTALL@}} make targets.  Add @code{$@{SURF_CRT0@}} to
 | |
| the dependencies for the @code{all} target and add
 | |
| @code{$@{SURF_INSTALL@}} to the dependencies for the @code{install}
 | |
| target.  Now, when libgloss is built and installed, support for your
 | |
| BSP will be installed as well.
 | |
| 
 | |
| @node GCC, Libraries, Libgloss, Top
 | |
| @chapter Porting GCC
 | |
| 
 | |
| Porting GCC requires two things, neither of which has anything to do
 | |
| with GCC. If GCC already supports a processor type, then all the work in
 | |
| porting GCC is really a linker issue. All GCC has to do is produce
 | |
| assembler output in the proper syntax. Most of the work is done by the
 | |
| linker, which is described elsewhere.
 | |
| 
 | |
| Mostly all GCC does is format the command line for the linker pass. The
 | |
| command line for GCC is set in the various config subdirectories of gcc.
 | |
| The options of interest to us are @code{CPP_SPEC} and
 | |
| @code{STARTFILE_SPEC}. CPP_SPEC sets the builtin defines for your
 | |
| environment. If you support multiple environments with the same
 | |
| processor, then OS specific defines will need to be elsewhere. 
 | |
| @c FIXME: Check these names
 | |
| 
 | |
| @code{STARTFILE_SPEC}
 | |
| 
 | |
| Once you have linker support, GCC will be able to produce a fully linked
 | |
| executable image. The only @emph{part} of GCC that the linker wants is a
 | |
| crt0.o, and a memory map. If you plan on running any programs that do
 | |
| I/O of any kind, you'll need to write support for the C library, which
 | |
| is described elsewhere. 
 | |
| 
 | |
| @menu
 | |
| * Overview::            An overview as to the compilation passes.
 | |
| * Options::             Useful GCC options for embedded systems.
 | |
| @end menu
 | |
| 
 | |
| @node Overview, Options, , GCC
 | |
| @section Compilation passes
 | |
| 
 | |
| GCC by itself only compiles the C or C++ code into assembler. Typically
 | |
| GCC invokes all the passes required for you. These passes are cpp, cc1,
 | |
| gas, ld. @code{cpp} is the C preprocessor. This will merge in the
 | |
| include files, expand all macros definitions, and process all the
 | |
| @code{#ifdef} sections. To see the output of ccp, invoke gcc with the
 | |
| @code{-E} option, and the preprocessed file will be printed on the
 | |
| stdout. cc1 is the actual compiler pass that produces the assembler for
 | |
| the processed file. GCC is actually only a driver program for all the
 | |
| compiler passes. It will format command line options for the other passes.
 | |
| The usual command line GCC uses for the final link phase will have LD
 | |
| link in the startup code and additional libraries by default.
 | |
| 
 | |
| GNU AS started it's life to only function as a compiler pass, but
 | |
| these days it can also be used as a source level assembler. When used as
 | |
| a source level assembler, it has a companion assembler preprocessor
 | |
| called @code{gasp}. This has a syntax similar to most other assembler
 | |
| macros packages. GAS emits a relocatable object file from the assembler
 | |
| source. The object file contains the executable part of the application,
 | |
| and debug symbols.
 | |
| 
 | |
| LD is responsible for resolving the addresses and symbols to something
 | |
| that will be fully self-contained. Some RTOS's use relocatable object
 | |
| file formats like @code{a.out}, but more commonly the final image will
 | |
| only use absolute addresses for symbols. This enables code to be burned
 | |
| into PROMS as well. Although LD can produce an executable image, there
 | |
| is usually a hidden object file called @code{crt0.o} that is required as
 | |
| startup code.  With this startup code and a memory map, the executable
 | |
| image will actually run on the target environment. @ref{Crt0,,Startup
 | |
| Files}.
 | |
| 
 | |
| The startup code usually defines a special symbol like @code{_start}
 | |
| that is the default base address for the application, and the first
 | |
| symbol in the executable image. If you plan to use any routines from the
 | |
| standard C library, you'll also need to implement the functions that
 | |
| this library is dependent on. @ref{Libraries,,Porting Newlib}.
 | |
| 
 | |
| @node Options, , Overview, GCC
 | |
| @c FIXME: Need stuff here about -fpic, -Ttext, etc...
 | |
| 
 | |
| Options for the various development tools are covered in more detail
 | |
| elsewhere. Still, the amount of options can be an overwhelming amount of
 | |
| stuff, so the options most suited to embedded systems are summarized
 | |
| here. If you use GCC as the main driver for all the passes, most of the
 | |
| linker options can be passed directly to the compiler. There are also
 | |
| GCC options that control how the GCC driver formats the command line
 | |
| arguments for the linker.
 | |
| 
 | |
| @menu
 | |
| * GCC Options::         Options for the compiler.
 | |
| * GAS Options::         Options for the assembler.
 | |
| * LD Options::          Options for the linker.
 | |
| @end menu
 | |
| 
 | |
| @node GCC Options, GAS Options, , Options
 | |
| Most of the GCC options that we're interested control how the GCC driver
 | |
| formats the options for the linker pass. 
 | |
| 
 | |
| @c FIXME: this section is still under work.
 | |
| @table @code
 | |
| @item -nostartfiles
 | |
| @item -nostdlib
 | |
| @item -Xlinker
 | |
| Pass the next option directly to the linker.
 | |
| 
 | |
| @item -v
 | |
| @item -fpic
 | |
| @end table
 | |
| 
 | |
| @node GAS Options, LD Options, GCC Options, Options
 | |
| @c FIXME: Needs stuff here
 | |
| 
 | |
| @node LD Options, , GAS Options, Options
 | |
| @c FIXME: Needs stuff here
 | |
| 
 | |
| 
 | |
| @node Libraries, GDB, GCC, Top
 | |
| @chapter Porting newlib
 | |
| 
 | |
| @menu
 | |
| * Crt0::                Crt0.S.
 | |
| * Linker Scripts::      Linker scripts for memory management.
 | |
| * What to do now::      Tricks for manipulating formats.
 | |
| * Libc::                Making libc work.
 | |
| @end menu
 | |
| 
 | |
| @node Crt0, Linker Scripts, , Libraries
 | |
| @section Crt0, the main startup file
 | |
|        
 | |
| To make a program that has been compiled with GCC to run, you
 | |
| need to write some startup code. The initial piece of startup code is
 | |
| called a crt0. (C RunTime 0) This is usually written in assembler, and
 | |
| it's object gets linked in first, and bootstraps the rest of the
 | |
| application when executed. This file needs to do the following things.
 | |
| 
 | |
| @enumerate
 | |
| @item
 | |
| Initialize anything that needs it. This init section varies. If you are
 | |
| developing an application that gets download to a ROM monitor, then
 | |
| there is usually no need for any special initialization. The ROM monitor
 | |
| handles it for you.
 | |
| 
 | |
| If you plan to burn your code in a ROM, then the crt0 typically has to
 | |
| do all the hardware initialization that is required to run an
 | |
| application. This can include things like initializing serial ports or
 | |
| run a memory check. It all depends on the hardware. 
 | |
|     
 | |
| @item
 | |
| Zero the BSS section. This is for uninitialized data. All the addresses in
 | |
| this section need to be initialized to zero so that programs that forget
 | |
| to check new variables default value will get unpredictable results.
 | |
| 
 | |
| @item
 | |
| Call main()
 | |
| This is what basically starts things running. If your ROM monitor
 | |
| supports it, then first setup argc and argv for command line arguments
 | |
| and an environment pointer. Then branch to main(). For G++ the the main
 | |
| routine gets a branch to __main inserted by the code generator at the
 | |
| very top.  __main() is used by G++ to initialize it's internal tables.
 | |
| __main() then returns back to your original main() and your code gets
 | |
| executed.
 | |
| 
 | |
| @item
 | |
| Call exit()
 | |
| After main() has returned, you need to cleanup things and return control
 | |
| of the hardware from the application. On some hardware, there is nothing
 | |
| to return to, especially if your program is in ROM.  Sometimes the best
 | |
| thing to do in this case is do a hardware reset, or branch back to the
 | |
| start address all over again.
 | |
| 
 | |
| When there is a ROM monitor present, usually a user trap can be called
 | |
| and then the ROM takes over. Pick a safe vector with no side
 | |
| effects. Some ROMs have a builtin trap handler just for this case.
 | |
| @end enumerate
 | |
| portable between all the m68k based boards we have here.
 | |
| @ref{crt0.S,,Example Crt0.S}. 
 | |
| 
 | |
| 
 | |
| @smallexample
 | |
| /* ANSI concatenation macros.  */
 | |
| 
 | |
| #define CONCAT1(a, b) CONCAT2(a, b)
 | |
| #define CONCAT2(a, b) a ## b
 | |
| @end smallexample
 | |
| These we'll use later.
 | |
| 
 | |
| @smallexample
 | |
| /* These are predefined by new versions of GNU cpp.  */
 | |
| 
 | |
| #ifndef __USER_LABEL_PREFIX__
 | |
| #define __USER_LABEL_PREFIX__ _
 | |
| #endif
 | |
| 
 | |
| /* Use the right prefix for global labels.  */
 | |
| #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
 | |
| 
 | |
| @end smallexample
 | |
| 
 | |
| These macros are to make this code portable between both @emph{COFF} and
 | |
| @emph{a.out}. @emph{COFF} always has an @var{_ (underline)} prepended on
 | |
| the front of all global symbol names. @emph{a.out} has none.
 | |
| 
 | |
| @smallexample
 | |
| #ifndef __REGISTER_PREFIX__
 | |
| #define __REGISTER_PREFIX__
 | |
| #endif
 | |
| 
 | |
| /* Use the right prefix for registers.  */
 | |
| #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
 | |
| 
 | |
| #define d0 REG (d0)
 | |
| #define d1 REG (d1)
 | |
| #define d2 REG (d2)
 | |
| #define d3 REG (d3)
 | |
| #define d4 REG (d4)
 | |
| #define d5 REG (d5)
 | |
| #define d6 REG (d6)
 | |
| #define d7 REG (d7)
 | |
| #define a0 REG (a0)
 | |
| #define a1 REG (a1)
 | |
| #define a2 REG (a2)
 | |
| #define a3 REG (a3)
 | |
| #define a4 REG (a4)
 | |
| #define a5 REG (a5)
 | |
| #define a6 REG (a6)
 | |
| #define fp REG (fp)
 | |
| #define sp REG (sp)
 | |
| @end smallexample
 | |
| 
 | |
| This is for portability between assemblers. Some register names have a
 | |
| @var{%} or @var{$} prepended to the register name.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * Set up some room for a stack. We just grab a chunk of memory.
 | |
|  */
 | |
| 	.set	stack_size, 0x2000
 | |
| 	.comm	SYM (stack), stack_size
 | |
| @end smallexample
 | |
| 
 | |
| Set up space for the stack. This can also be done in the linker script,
 | |
| but it typically gets done here.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * Define an empty environment.
 | |
|  */
 | |
|         .data
 | |
|         .align 2
 | |
| SYM (environ):
 | |
|         .long 0
 | |
| @end smallexample
 | |
| 
 | |
| Set up an empty space for the environment. This is bogus on any most ROM 
 | |
| monitor, but we setup a valid address for it, and pass it to main. At
 | |
| least that way if an application checks for it, it won't crash.
 | |
| 
 | |
| @smallexample
 | |
|  	.align	2
 | |
| 	.text
 | |
| 	.global SYM (stack)
 | |
| 
 | |
| 	.global SYM (main)
 | |
| 	.global SYM (exit)
 | |
| /* 
 | |
|  * This really should be __bss_start, not SYM (__bss_start).
 | |
|  */
 | |
| 	.global __bss_start
 | |
| @end smallexample
 | |
| 
 | |
| Setup a few global symbols that get used elsewhere. @var{__bss_start}
 | |
| needs to be unchanged, as it's setup by the linker script.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * start -- set things up so the application will run.
 | |
|  */
 | |
| SYM (start):
 | |
| 	link	a6, #-8
 | |
| 	moveal	#SYM (stack) + stack_size, sp
 | |
| 
 | |
| /*
 | |
|  * zerobss -- zero out the bss section
 | |
|  */
 | |
| 	moveal	#__bss_start, a0
 | |
| 	moveal	#SYM (end), a1
 | |
| 1:
 | |
| 	movel	#0, (a0)
 | |
| 	leal	4(a0), a0
 | |
| 	cmpal	a0, a1
 | |
| 	bne	1b
 | |
| @end smallexample
 | |
| 
 | |
| The global symbol @code{start} is used by the linker as the default
 | |
| address to use for the @code{.text} section. then it zeros the
 | |
| @code{.bss} section so the uninitialized data will all be cleared. Some
 | |
| programs have wild side effects from having the .bss section let
 | |
| uncleared. Particularly it causes problems with some implementations of
 | |
| @code{malloc}. 
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * Call the main routine from the application to get it going.
 | |
|  * main (argc, argv, environ)
 | |
|  * We pass argv as a pointer to NULL.
 | |
|  */
 | |
|         pea     0
 | |
|         pea     SYM (environ)
 | |
|         pea     sp@@(4)
 | |
|         pea     0
 | |
| 	jsr	SYM (main)
 | |
| 	movel	d0, sp@@-
 | |
| @end smallexample
 | |
| 
 | |
| Setup the environment pointer and jump to @code{main()}. When
 | |
| @code{main()} returns, it drops down to the @code{exit} routine below.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * _exit -- Exit from the application. Normally we cause a user trap
 | |
|  *          to return to the ROM monitor for another run.
 | |
|  */
 | |
| SYM (exit):
 | |
| 	trap	#0
 | |
| @end smallexample
 | |
| 
 | |
| Implementing @code{exit} here is easy. Both the @code{rom68k} and @code{bug}
 | |
| can handle a user caused exception of @code{zero} with no side effects.
 | |
| Although the @code{bug} monitor has a user caused trap that will return
 | |
| control to the ROM monitor, this solution has been more portable.
 | |
| 
 | |
| @node Linker Scripts, What to do now, Crt0, Libraries
 | |
| @section Linker scripts for memory management
 | |
| 
 | |
| The linker script sets up the memory map of an application. It also
 | |
| sets up default values for variables used elsewhere by sbrk() and the
 | |
| crt0. These default variables are typically called @code{_bss_start} and
 | |
| @code{_end}.
 | |
| 
 | |
| For G++, the constructor and destructor tables must also be setup here.
 | |
| The actual section names vary depending on the object file format. For
 | |
| @code{a.out} and @code{coff}, the three main sections are @code{.text},
 | |
| @code{.data}, and @code{.bss}.
 | |
| 
 | |
| Now that you have an image, you can test to make sure it got the
 | |
| memory map right. You can do this by having the linker create a memory
 | |
| map (by using the @code{-Map} option), or afterwards by using @code{nm} to
 | |
| check a few critical addresses like @code{start}, @code{bss_end}, and
 | |
| @code{_etext}.
 | |
| 
 | |
| Here's a breakdown of a linker script for a m68k based target board.
 | |
| See the file @code{libgloss/m68k/idp.ld}, or go to the appendixes in
 | |
| the end of the manual. @ref{idp.ld,,Example Linker Script}. 
 | |
| 
 | |
| @smallexample
 | |
| STARTUP(crt0.o)
 | |
| OUTPUT_ARCH(m68k)
 | |
| INPUT(idp.o)
 | |
| SEARCH_DIR(.)
 | |
| __DYNAMIC  =  0;
 | |
| @end smallexample
 | |
| 
 | |
| The @code{STARTUP} command loads the file specified so that it's
 | |
| first. In this case it also doubles to load the file as well, because
 | |
| the m68k-coff configuration defaults to not linking in the crt0.o by
 | |
| default. It assumes that the developer probably has their own crt0.o.
 | |
| This behavior is controlled in the config file for each architecture.
 | |
| It's a macro called @code{STARTFILE_SPEC}, and if it's set to
 | |
| @code{null}, then when @code{gcc} formats it's command line, it doesn't
 | |
| add @code{crto.o}. Any file name can be specified here, but the default
 | |
| is always @code{crt0.o}.
 | |
| 
 | |
| Course if you only use @code{ld} to link, then the control of whether or
 | |
| not to link in @code{crt0.o} is done on the command line. If you have
 | |
| multiple crto files, then you can leave this out all together, and link
 | |
| in the @code{crt0.o} in the makefile, or by having different linker
 | |
| scripts. Sometimes this is done for initializing floating point
 | |
| optionally, or to add device support.
 | |
| 
 | |
| The @code{OUTPUT_ARCH} sets architecture the output file is for.
 | |
| 
 | |
| @code{INPUT} loads in the file specified. In this case, it's a relocated
 | |
| library that contains the definitions for the low-level functions need
 | |
| by libc.a.  This could have also been specified on the command line, but
 | |
| as it's always needed, it might as well be here as a default.
 | |
| @code{SEARCH_DIR} specifies the path to look for files, and
 | |
| @code{_DYNAMIC} means in this case there are no shared libraries. 
 | |
| 
 | |
| @c FIXME: Check the linker manual to make sure this is accurate.
 | |
| @smallexample
 | |
| /*
 | |
|  * Setup the memory map of the MC68ec0x0 Board (IDP)
 | |
|  * stack grows up towards high memory. This works for
 | |
|  * both the rom68k and the mon68k monitors.
 | |
|  */
 | |
| MEMORY
 | |
| @{
 | |
|   ram     : ORIGIN = 0x10000, LENGTH = 2M
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| This specifies a name for a section that can be referred to later in the 
 | |
| script. In this case, it's only a pointer to the beginning of free RAM
 | |
| space, with an upper limit at 2M. If the output file exceeds the upper
 | |
| limit, it will produce an error message.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * stick everything in ram (of course)
 | |
|  */
 | |
| SECTIONS
 | |
| @{
 | |
|   .text :
 | |
|   @{
 | |
|     CREATE_OBJECT_SYMBOLS
 | |
|     *(.text)
 | |
|      etext  =  .;
 | |
|      __CTOR_LIST__ = .;
 | |
|      LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
 | |
|     *(.ctors)
 | |
|      LONG(0)
 | |
|      __CTOR_END__ = .;
 | |
|      __DTOR_LIST__ = .;
 | |
|      LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
 | |
|     *(.dtors)
 | |
|      LONG(0)
 | |
|      __DTOR_END__ = .;
 | |
|     *(.lit)
 | |
|     *(.shdata)
 | |
|   @}  > ram
 | |
|   .shbss SIZEOF(.text) + ADDR(.text) :	@{
 | |
|     *(.shbss)
 | |
|   @}
 | |
| @end smallexample
 | |
| 
 | |
| Set up the @code{.text} section. In a @code{COFF} file, .text is where
 | |
| all the actual instructions are. This also sets up the @emph{CONTRUCTOR}
 | |
| and the @emph{DESTRUCTOR} tables for @code{G++}. Notice that the section
 | |
| description redirects itself to the @emph{ram} variable setup earlier.
 | |
| 
 | |
| @smallexample
 | |
|   .talias :	 @{ @}  > ram
 | |
|   .data  : @{
 | |
|     *(.data)
 | |
|     CONSTRUCTORS
 | |
|     _edata  =  .;
 | |
|   @} > ram
 | |
| @end smallexample
 | |
| 
 | |
| Setup the @code{.data} section. In a @code{coff} file, this is where all
 | |
| he initialized data goes. @code{CONSTRUCTORS} is a special command used
 | |
| by @code{ld}.
 | |
| 
 | |
| @smallexample
 | |
|   .bss SIZEOF(.data) + ADDR(.data) :
 | |
|   @{
 | |
|    __bss_start = ALIGN(0x8);
 | |
|    *(.bss)
 | |
|    *(COMMON)
 | |
|       end = ALIGN(0x8);
 | |
|       _end = ALIGN(0x8);
 | |
|       __end = ALIGN(0x8);
 | |
|   @}
 | |
|   .mstack  : @{ @}  > ram
 | |
|   .rstack  : @{ @}  > ram
 | |
|   .stab  . (NOLOAD) : 
 | |
|   @{
 | |
|     [ .stab ]
 | |
|   @}
 | |
|   .stabstr  . (NOLOAD) :
 | |
|   @{
 | |
|     [ .stabstr ]
 | |
|   @}
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| Setup the @code{.bss} section. In a @code{COFF} file, this is where
 | |
| unitialized data goes. The symbols @code{_bss_start} and @code{_end}
 | |
| are setup here for use by the @code{crt0.o} when it zero's the
 | |
| @code{.bss} section. 
 | |
| 
 | |
| 
 | |
| @node What to do now, Libc, Linker Scripts, Libraries
 | |
| @section What to do when you have a binary image
 | |
| 
 | |
| A few ROM monitors load binary images, typically @code{a.out}, but most all
 | |
| will load an @code{srecord}. An srecord is an ASCII representation of a binary 
 | |
| image. At it's simplest, an srecord is an address, followed by a byte
 | |
| count, followed by the bytes, and a 2's compliment checksum. A whole
 | |
| srecord file has an optional @emph{start} record, and a required @emph{end} 
 | |
| record. To make an srecord from a binary image, the GNU @code{objcopy} program
 | |
| is used. This will read the image and make an srecord from it. To do
 | |
| this, invoke objcopy like this: @code{objcopy -O srec infile outfile}. Most
 | |
| PROM burners also read srecords or a similar format. Use @code{objdump -i} to
 | |
| get a list of support object files types for your architecture. 
 | |
| 
 | |
| @node Libc, , What to do now, Libraries
 | |
| @section Libraries
 | |
| 
 | |
| This describes @code{newlib}, a freely available libc replacement. Most
 | |
| applications use calls in the standard C library. When initially linking
 | |
| in libc.a, several I/O functions are undefined. If you don't plan on
 | |
| doing any I/O, then you're OK, otherwise they need to be created. These
 | |
| routines are read, write, open, close. sbrk, and kill. Open & close
 | |
| don't need to be fully supported unless you have a filesystems, so
 | |
| typically they are stubbed out. Kill is also a stub, since you can't do
 | |
| process control on an embedded system. 
 | |
| 
 | |
| Sbrk() is only needed by applications that do dynamic memory
 | |
| allocation. It's uses the symbol @code{_end} that is setup in the linker
 | |
| script. It also requires a compile time option to set the upper size
 | |
| limit on the heap space. This leaves us with read and write, which are
 | |
| required for serial I/O. Usually these two routines are written in C,
 | |
| and call a lower level function for the actual I/O operation. These two
 | |
| lowest level I/O primitives are inbyte() and outbyte(), and are also
 | |
| used by GDB back ends if you've written an exception handler. Some
 | |
| systems also implement a havebyte() for input as well. 
 | |
| 
 | |
| Other commonly included functions are routines for manipulating
 | |
| LED's on the target (if they exist) or low level debug help. Typically a
 | |
| putnum() for printing words and bytes as a hex number is helpful, as
 | |
| well as a low-level print() to output simple strings. 
 | |
| 
 | |
| As libg++ uses the I/O routines in libc.a, if read and write work,
 | |
| then libg++ will also work with no additional changes. 
 | |
| 
 | |
| @menu
 | |
| * I/O Support::         Functions that make serial I/O work.
 | |
| * Memory Support::      Memory support.
 | |
| * Misc Support::        Other needed functions.
 | |
| * Debugging::            Useful Debugging Functions
 | |
| @end menu
 | |
| 
 | |
| @node I/O Support, Memory Support, , Libc
 | |
| @subsection Making I/O work
 | |
| 
 | |
| @node Memory Support, Misc Support, I/O Support, Libc
 | |
| @subsection Routines for dynamic memory allocation
 | |
| To support using any of the memory functions, you need to implement
 | |
| sbrk(). @code{malloc()}, @code{calloc()}, and @code{realloc()} all call
 | |
| @code{sbrk()} at there lowest level. @code{caddr_t} is defined elsewhere
 | |
| as @code{char *}. @code{RAMSIZE} is presently a compile time option. All
 | |
| this does is move a pointer to heap memory and check for the upper
 | |
| limit. @ref{glue.c,,Example libc support code}. @code{sbrk()} returns a
 | |
| pointer to the previous value before more memory was allocated.
 | |
| 
 | |
| @smallexample
 | |
| /* _end is set in the linker command file *
 | |
| extern caddr_t _end;/
 | |
| 
 | |
| /* just in case, most boards have at least some memory */
 | |
| #ifndef RAMSIZE
 | |
| #  define RAMSIZE             (caddr_t)0x100000
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * sbrk -- changes heap size size. Get nbytes more
 | |
|  *         RAM. We just increment a pointer in what's
 | |
|  *         left of memory on the board.
 | |
|  */
 | |
| caddr_t
 | |
| sbrk(nbytes)
 | |
|      int nbytes;
 | |
| @{
 | |
|   static caddr_t heap_ptr = NULL;
 | |
|   caddr_t        base;
 | |
| 
 | |
|   if (heap_ptr == NULL) @{
 | |
|     heap_ptr = (caddr_t)&_end;
 | |
|   @}
 | |
| 
 | |
|   if ((RAMSIZE - heap_ptr) >= 0) @{
 | |
|     base = heap_ptr;
 | |
|     heap_ptr += nbytes;
 | |
|     return (base);
 | |
|   @} else @{
 | |
|     errno = ENOMEM;
 | |
|     return ((caddr_t)-1);
 | |
|   @}
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| @node Misc Support, Debugging, Memory Support, Libc
 | |
| @subsection Misc support routines
 | |
| 
 | |
| These are called by @code{newlib} but don't apply to the embedded
 | |
| environment. @code{isatty()} is self explanatory. @code{kill()} doesn't
 | |
| apply either in an environment withno process control, so it justs
 | |
| exits, which is a similar enough behavior. @code{getpid()} can safely
 | |
| return any value greater than 1. The value doesn't effect anything in
 | |
| @code{newlib} because once again there is no process control.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * isatty -- returns 1 if connected to a terminal device,
 | |
|  *           returns 0 if not. Since we're hooked up to a
 | |
|  *           serial port, we'll say yes and return a 1.
 | |
|  */
 | |
| int
 | |
| isatty(fd)
 | |
|      int fd;
 | |
| @{
 | |
|   return (1);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * getpid -- only one process, so just return 1.
 | |
|  */
 | |
| #define __MYPID 1
 | |
| int
 | |
| getpid()
 | |
| @{
 | |
|   return __MYPID;
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * kill -- go out via exit...
 | |
|  */
 | |
| int
 | |
| kill(pid, sig)
 | |
|      int pid;
 | |
|      int sig;
 | |
| @{
 | |
|   if(pid == __MYPID)
 | |
|     _exit(sig);
 | |
|   return 0;
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| @node Debugging, , Misc Support, Libc
 | |
| @subsection Useful debugging functions
 | |
| 
 | |
| There are always a few useful functions for debugging your project in
 | |
| progress. I typically implement a simple @code{print()} routine that
 | |
| runs standalone in liblgoss, with no @code{newlib} support. The I/O
 | |
| function @code{outbyte()} can also be used for low level debugging. Many
 | |
| times print will work when there are problems that cause @code{printf()} to
 | |
| cause an exception. @code{putnum()} is just to print out values in hex
 | |
| so they are easier to read.
 | |
| 
 | |
| @smallexample
 | |
| /*
 | |
|  * print -- do a raw print of a string
 | |
|  */ 
 | |
| int
 | |
| print(ptr)
 | |
| char *ptr;
 | |
| @{
 | |
|   while (*ptr) @{
 | |
|     outbyte (*ptr++);
 | |
|   @}
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * putnum -- print a 32 bit number in hex
 | |
|  */
 | |
| int
 | |
| putnum (num)
 | |
| unsigned int num;
 | |
| @{
 | |
|   char  buffer[9];
 | |
|   int   count;
 | |
|   char  *bufptr = buffer;
 | |
|   int   digit;
 | |
|   
 | |
|   for (count = 7 ; count >= 0 ; count--) @{
 | |
|     digit = (num >> (count * 4)) & 0xf;
 | |
|     
 | |
|     if (digit <= 9)
 | |
|       *bufptr++ = (char) ('0' + digit);
 | |
|     else
 | |
|       *bufptr++ = (char) ('a' - 10 + digit);
 | |
|   @}
 | |
| 
 | |
|   *bufptr = (char) 0;
 | |
|   print (buffer);
 | |
|   return;
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| If there are LEDs on the board, they can also be put to use for
 | |
| debugging when the serial I/O code is being written. I usually implement
 | |
| a @code{zylons()} function, which strobes the LEDS (if there is more
 | |
| than one) in sequence, creating a rotating effect. This is convenient
 | |
| between I/O to see if the target is still alive. Another useful LED
 | |
| function is @code{led_putnum()}, which takes a digit and displays it as
 | |
| a bit pattern or number. These usually have to be written in assembler
 | |
| for each target board. Here are a number of C based routines that may be
 | |
| useful.
 | |
| 
 | |
| @code{led_putnum()} puts a number on a single digit segmented
 | |
| LED display. This LED is set by setting a bit mask to an address, where
 | |
| 1 turns the segment off, and 0 turns it on. There is also a little
 | |
| decimal point on the LED display, so it gets the leftmost bit. The other
 | |
| bits specify the segment location. The bits look like:
 | |
| 
 | |
| @smallexample
 | |
|         [d.p | g | f | e | d | c | b | a ] is the byte.
 | |
| @end smallexample
 | |
| 
 | |
| The locations are set up as:
 | |
| 
 | |
| @smallexample 
 | |
|              a
 | |
|            -----
 | |
|         f |     | b
 | |
|           |  g  |
 | |
|            -----
 | |
|           |     |
 | |
|         e |     | c
 | |
|            -----
 | |
|              d
 | |
| @end smallexample
 | |
| 
 | |
| This takes a number that's already been converted to a string, and
 | |
| prints it. 
 | |
| 
 | |
| @smallexample
 | |
| #define LED_ADDR	0xd00003
 | |
| 
 | |
| void
 | |
| led_putnum ( num )
 | |
| char num;
 | |
| @{
 | |
|     static unsigned char *leds = (unsigned char *)LED_ADDR;
 | |
|     static unsigned char num_bits [18] = @{
 | |
|       0xff,						/* clear all */
 | |
|       0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, /* numbers 0-9 */
 | |
|       0x98, 0x20, 0x3, 0x27, 0x21, 0x4, 0xe 		/* letters a-f */
 | |
|     @};
 | |
| 
 | |
|     if (num >= '0' && num <= '9')
 | |
|       num = (num - '0') + 1;
 | |
| 
 | |
|     if (num >= 'a' && num <= 'f')
 | |
|       num = (num - 'a') + 12;
 | |
| 
 | |
|     if (num == ' ')
 | |
|       num = 0;
 | |
| 
 | |
|     *leds = num_bits[num];
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * zylons -- draw a rotating pattern. NOTE: this function never returns.
 | |
|  */
 | |
| void
 | |
| zylons()
 | |
| @{
 | |
|   unsigned char *leds 	= (unsigned char *)LED_ADDR;
 | |
|   unsigned char curled = 0xfe;
 | |
| 
 | |
|   while (1)
 | |
|     @{
 | |
|       *leds = curled;
 | |
|       curled = (curled >> 1) | (curled << 7);
 | |
|       delay ( 200 );
 | |
|     @}
 | |
| @}
 | |
| @end smallexample
 | |
| 
 | |
| 
 | |
| @node GDB, Binutils, Libraries, Top
 | |
| @chapter Writing a new GDB backend
 | |
| 
 | |
| Typically, either the low-level I/O routines are used for debugging, or
 | |
| LEDs, if present. It is much easier to use GDb for debugging an
 | |
| application. There are several different techniques used to have GDB work
 | |
| remotely. Commonly more than one kind of GDB interface is used to cober
 | |
| a wide variety of development needs.
 | |
| 
 | |
| The most common style of GDB backend is an exception handler for
 | |
| breakpoints. This is also called a @emph{gdb stub}, and is requires the
 | |
| two additional lines of init code in your @code{main()} routine. The GDB
 | |
| stubs all use the GDB @emph{remote protocol}. When the application gets a
 | |
| breakpoint exception, it communicates to GDB on the host.
 | |
| 
 | |
| Another common style of interfacing GDB to a target is by using an
 | |
| existing ROM monitor. These break down into two main kinds, a similar
 | |
| protocol to the GDB remote protocol, and an interface that uses the ROM
 | |
| monitor directly. This kind has GDB simulating a human operator, and all
 | |
| GDB does is work as a command formatter and parser. 
 | |
| 
 | |
| @menu
 | |
| * GNU remote protocol::         The standard remote protocol.
 | |
| * Exception handler::           A linked in exception handler.
 | |
| * ROM monitors::                Using a ROM monitor as a backend.
 | |
| * Other remote protocols::      Adding support for new protocols.
 | |
| @end menu
 | |
| 
 | |
| @node GNU remote protocol, Exception handler, ,GDB
 | |
| @section The standard remote protocol
 | |
| 
 | |
| The standard remote protocol is a simple, packet based scheme. A debug
 | |
| packet whose contents are @emph{<data>} is encapsulated for transmission
 | |
| in the form:
 | |
| 
 | |
| @smallexample
 | |
| 	$ <data> # CSUM1 CSUM2
 | |
| @end smallexample
 | |
| 
 | |
| @emph{<data>} must be ASCII alphanumeric and cannot include characters
 | |
| @code{$} or @code{#}.  If @emph{<data>} starts with two characters
 | |
| followed by @code{:}, then the existing stubs interpret this as a
 | |
| sequence number. For example, the command @code{g} is used to read the
 | |
| values of the registers. So, a packet to do this would look like
 | |
| 
 | |
| @smallexample
 | |
|         $g#67
 | |
| @end smallexample
 | |
| 
 | |
| @emph{CSUM1} and @emph{CSUM2} are an ascii representation in hex of an
 | |
| 8-bit checksum of @emph{<data>}, the most significant nibble is sent first.
 | |
| the hex digits 0-9,a-f are used.
 | |
| 
 | |
| A simple protocol is used when communicating with the target. This is
 | |
| mainly to give a degree of error handling over the serial cable. For
 | |
| each packet transmitted successfully, the target responds with a
 | |
| @code{+} (@code{ACK}). If there was a transmission error, then the target
 | |
| responds with a @code{-} (@code{NAK}). An error is determined when the
 | |
| checksum doesn't match the calculated checksum for that data record.
 | |
| Upon reciept of the @code{ACK}, @code{GDB} can then transmit the next
 | |
| packet. 
 | |
| 
 | |
| Here is a list of the main functions that need to be supported. Each data
 | |
| packet is a command with a set number of bytes in the command packet.
 | |
| Most commands either return data, or respond with a @code{NAK}. Commands
 | |
| that don't return data respond with an @code{ACK}. All data values are
 | |
| ascii hex digits. Every byte needs two hex digits to represent t. This
 | |
| means that a byte with the value @samp{7} becomes @samp{07}. On a 32 bit
 | |
| machine this works out to 8 characters per word. All of the bytes in a
 | |
| word are stored in the target byte order. When writing the host side of
 | |
| the GDB protocol, be careful of byte order, and make sure that the code
 | |
| will run on both big and little endian hosts and produce the same answers.
 | |
| 
 | |
| These functions are the minimum required to make a GDB backend work. All
 | |
| other commands are optional, and not supported by all GDB backends.
 | |
| 
 | |
| @table @samp
 | |
| @item  read registers  @code{g}
 | |
| 
 | |
| returns @code{XXXXXXXX...}
 | |
| 
 | |
| Registers are in the internal order for GDB, and the bytes in a register
 | |
| are in the same order the machine uses. All values are in sequence
 | |
| starting with register 0. All registers are listed in the same packet. A
 | |
| sample packet would look like @code{$g#}.
 | |
| 
 | |
| @item	write registers	@code{GXXXXXXXX...}
 | |
| @code{XXXXXXXX} is the value to set the register to.  Registers are in
 | |
| the internal order for GDB, and the bytes in a register are in the same
 | |
| order the machine uses. All values are in sequence starting with
 | |
| register 0. All registers values are listed in the same packet. A sample
 | |
| packet would look like @code{$G000000001111111122222222...#}
 | |
| 
 | |
| returns @code{ACK} or @code{NAK}
 | |
| 
 | |
| @item	read memory     @code{mAAAAAAAA,LLLL}
 | |
| @code{AAAAAAAA} is address, @code{LLLL} is length. A sample packet would
 | |
| look like @code{$m00005556,0024#}. This would request 24 bytes starting
 | |
| at address @emph{00005556}
 | |
| 
 | |
| returns @code{XXXXXXXX...}
 | |
| @code{XXXXXXXX} is the memory contents. Fewer bytes than requested will
 | |
| be returned if only part of the data can be read. This can be determined
 | |
| by counting the values till the end of packet @code{#} is seen and
 | |
| comparing that with the total count of bytes that was requested.
 | |
| 
 | |
| @item	write memory	@code{MAAAAAAAA,LLLL:XXXXXXXX}
 | |
| @code{AAAAAAAA} is the starting address, @code{LLLL} is the number of
 | |
| bytes to be written, and @code{XXXXXXXX} is value to be written. A
 | |
| sample packet would look like
 | |
| @code{$M00005556,0024:101010101111111100000000...#}
 | |
| 
 | |
| returns @code{ACK} or @code{NAK} for an error. @code{NAK} is also
 | |
| returned when only part of the data is written.
 | |
| 
 | |
| @item	continue	@code{cAAAAAAAAA}
 | |
| @code{AAAAAAAA} is address to resume execution at. If @code{AAAAAAAA} is
 | |
| omitted, resume at the curent address of the @code{pc} register.
 | |
| 
 | |
| returns the same replay as @code{last signal}. There is no immediate
 | |
| replay to @code{cont} until the next breakpoint is reached, and the
 | |
| program stops executing.
 | |
| 
 | |
| @item	step		sAA..AA
 | |
| @code{AA..AA} is address to resume
 | |
| If @code{AA..AA} is omitted, resume at same address.
 | |
| 
 | |
| returns the same replay as @code{last signal}. There is no immediate
 | |
| replay to @code{step} until the next breakpoint is reached, and the
 | |
| program stops executing.
 | |
| 
 | |
| @item	last signal     @code{?}
 | |
| 
 | |
| This returns one of the following:
 | |
| 
 | |
| @itemize @bullet
 | |
| @item @code{SAA}
 | |
| Where @code{AA} is the number of the last signal.
 | |
| Exceptions on the target are converted to the most similar Unix style
 | |
| signal number, like @code{SIGSEGV}. A sample response of this type would
 | |
| look like @code{$S05#}.
 | |
| 
 | |
| @item TAAnn:XXXXXXXX;nn:XXXXXXXX;nn:XXXXXXXX;
 | |
| @code{AA} is the signal number.
 | |
| @code{nn} is the register number.
 | |
| @code{XXXXXXXX} is the register value.
 | |
| 
 | |
| @item WAA
 | |
| The process exited, and @code{AA} is the exit status.  This is only
 | |
| applicable for certains sorts of targets.
 | |
| 
 | |
| @end itemize
 | |
| 
 | |
| These are used in some GDB backends, but not all. 
 | |
| 
 | |
| @item write reg         @code{Pnn=XXXXXXXX}
 | |
| Write register @code{nn} with value @code{XXXXXXXX}.
 | |
| 
 | |
| returns @code{ACK} or @code{NAK}
 | |
| 
 | |
| @item	kill request	k
 | |
| 
 | |
| @item	toggle debug	d
 | |
| toggle debug flag (see 386 & 68k stubs)
 | |
| 
 | |
| @item	reset		r
 | |
| reset -- see sparc stub.
 | |
| 
 | |
| @item	reserved	@code{other}
 | |
| On other requests, the stub should ignore the request and send an empty
 | |
| response @code{$#<checksum>}.  This way we can extend the protocol and GDB
 | |
| can tell whether the stub it is	talking to uses the old or the new.
 | |
| 
 | |
| @item	search		@code{tAA:PP,MM}
 | |
| Search backwards starting at address @code{AA} for a match with pattern
 | |
| PP and mask @code{MM}. @code{PP} and @code{MM} are 4 bytes.
 | |
| 
 | |
| @item	general query	@code{qXXXX}
 | |
| Request info about XXXX.
 | |
| 
 | |
| @item	general set	@code{QXXXX=yyyy}
 | |
| Set value of @code{XXXX} to @code{yyyy}.
 | |
| 
 | |
| @item	query sect offs	@code{qOffsets}
 | |
| Get section offsets.  Reply is @code{Text=xxx;Data=yyy;Bss=zzz}
 | |
| 
 | |
| @item	console output	Otext
 | |
| Send text to stdout. The text gets display from the target side of the
 | |
| serial connection.
 | |
| 
 | |
| @end table
 | |
| 
 | |
| Responses can be run-length encoded to save space.  A @code{*}means that
 | |
| the next character is an ASCII encoding giving a repeat count which
 | |
| stands for that many repetitions of the character preceding the @code{*}.
 | |
| The encoding is n+29, yielding a printable character where n >=3 
 | |
| (which is where run length encoding starts to win). You can't use a
 | |
| value of where n >126 because it's only a two byte value. An example
 | |
| would be a @code{0*03} means the same thing as @code{0000}.
 | |
| 
 | |
| @node Exception handler, ROM monitors, GNU remote protocol, GDB
 | |
| @section A linked in exception handler
 | |
| 
 | |
| A @emph{GDB stub} consists of two parts, support for the exception
 | |
| handler, and the exception handler itself. The exception handler needs
 | |
| to communicate to GDB on the host whenever there is a breakpoint
 | |
| exception. When GDB starts a program running on the target, it's polling
 | |
| the serial port during execution looking for any debug packets. So when
 | |
| a breakpoint occurs, the exception handler needs to save state, and send
 | |
| a GDB remote protocol packet to GDB on the host. GDB takes any output
 | |
| that isn't a debug command packet and displays it in the command window.
 | |
| 
 | |
| Support for the exception handler varies between processors, but the
 | |
| minimum supported functions are those needed by GDB. These are functions
 | |
| to support the reading and writing of registers, the reading and writing
 | |
| of memory, start execution at an address, single step, and last signal.
 | |
| Sometimes other functions for adjusting the baud rate, or resetting the
 | |
| hardware are implemented. 
 | |
| 
 | |
| Once GDB gets the command packet from the breakpoint, it will read a few
 | |
| registers and memory locations an then wait for the user. When the user
 | |
| types @code{run} or @code{continue} a @code{continue} command is issued
 | |
| to the backend, and control returns from the breakpoint routine to the
 | |
| application.
 | |
| 
 | |
| @node ROM monitors, Other remote protocols, Exception handler, GDB
 | |
| @section Using a ROM monitor as a backend
 | |
| GDB also can mimic a human user and use a ROM monitors normal debug
 | |
| commands as a backend. This consists mostly of sending and parsing
 | |
| @code{ASCII} strings. All the ROM monitor interfaces share a common set
 | |
| of routines in @code{gdb/monitor.c}. This supports adding new ROM
 | |
| monitor interfaces by filling in a structure with the common commands
 | |
| GDB needs. GDb already supports several command ROM monitors, including
 | |
| Motorola's @code{Bug} monitor for their VME boards, and the Rom68k
 | |
| monitor by Integrated Systems, Inc. for various m68k based boards. GDB
 | |
| also supports the custom ROM monitors on the WinBond and Oki PA based
 | |
| targets. There is builtin support for loading files to ROM monitors
 | |
| specifically. GDB can convert a binary into an srecord and then load it
 | |
| as an ascii file, or using @code{xmodem}.
 | |
| 
 | |
| @c FIXME: do I need trademark somethings here ? Is Integrated the right
 | |
| @c company? 
 | |
| 
 | |
| @node Other remote protocols, ,ROM monitors, GDB 
 | |
| @section Adding support for new protocols
 | |
| @c FIXME: write something here 
 | |
| 
 | |
| @node Binutils, Code Listings, GDB, Top
 | |
| 
 | |
| @node Code Listings, idp.ld, Binutils, Top
 | |
| @appendix Code Listings
 | |
| 
 | |
| @menu
 | |
| * idp.ld::              A m68k linker script.
 | |
| * crt0.S::              Crt0.S for an m68k.
 | |
| * glue.c::              C based support for for Stdio functions.
 | |
| * mvme.S::              Rom monitor based I/O support in assembler.
 | |
| * io.c::                C based for memory mapped I/O.
 | |
| * leds.c::              C based LED routines.
 | |
| @end menu
 | |
| 
 | |
| @node idp.ld, crt0.S, Code Listings, Code Listings
 | |
| @section Linker script for the IDP board
 | |
| 
 | |
| This is the linker script script that is used on the Motorola IDP board.
 | |
| 
 | |
| @example
 | |
| STARTUP(crt0.o)
 | |
| OUTPUT_ARCH(m68k)
 | |
| INPUT(idp.o)
 | |
| SEARCH_DIR(.)
 | |
| __DYNAMIC  =  0;
 | |
| /*
 | |
|  * Setup the memory map of the MC68ec0x0 Board (IDP)
 | |
|  * stack grows up towards high memory. This works for
 | |
|  * both the rom68k and the mon68k monitors.
 | |
|  */
 | |
| MEMORY
 | |
| @{
 | |
|   ram     : ORIGIN = 0x10000, LENGTH = 2M
 | |
| @}
 | |
| /*
 | |
|  * stick everything in ram (of course)
 | |
|  */
 | |
| SECTIONS
 | |
| @{
 | |
|   .text :
 | |
|   @{
 | |
|     CREATE_OBJECT_SYMBOLS
 | |
|     *(.text)
 | |
|      etext  =  .;
 | |
|      __CTOR_LIST__ = .;
 | |
|      LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
 | |
|     *(.ctors)
 | |
|      LONG(0)
 | |
|      __CTOR_END__ = .;
 | |
|      __DTOR_LIST__ = .;
 | |
|      LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
 | |
|     *(.dtors)
 | |
|      LONG(0)
 | |
|      __DTOR_END__ = .;
 | |
|     *(.lit)
 | |
|     *(.shdata)
 | |
|   @}  > ram
 | |
|   .shbss SIZEOF(.text) + ADDR(.text) :	@{
 | |
|     *(.shbss)
 | |
|   @} 
 | |
|   .talias :	 @{ @}  > ram
 | |
|   .data  : @{
 | |
|     *(.data)
 | |
|     CONSTRUCTORS
 | |
|     _edata  =  .;
 | |
|   @} > ram
 | |
| 
 | |
|   .bss SIZEOF(.data) + ADDR(.data) :
 | |
|   @{
 | |
|    __bss_start = ALIGN(0x8);
 | |
|    *(.bss)
 | |
|    *(COMMON)
 | |
|       end = ALIGN(0x8);
 | |
|       _end = ALIGN(0x8);
 | |
|       __end = ALIGN(0x8);
 | |
|   @}
 | |
|   .mstack  : @{ @}  > ram
 | |
|   .rstack  : @{ @}  > ram
 | |
|   .stab  . (NOLOAD) : 
 | |
|   @{
 | |
|     [ .stab ]
 | |
|   @}
 | |
|   .stabstr  . (NOLOAD) :
 | |
|   @{
 | |
|     [ .stabstr ]
 | |
|   @}
 | |
| @}
 | |
| @end example
 | |
| 
 | |
| @node crt0.S, glue.c, idp.ld, Code Listings
 | |
| @section crt0.S - The startup file
 | |
| 
 | |
| @example
 | |
| /*
 | |
|  * crt0.S -- startup file for m68k-coff
 | |
|  * 
 | |
|  */
 | |
| 
 | |
| 	.title "crt0.S for m68k-coff"
 | |
| 
 | |
| /* These are predefined by new versions of GNU cpp.  */
 | |
| 
 | |
| #ifndef __USER_LABEL_PREFIX__
 | |
| #define __USER_LABEL_PREFIX__ _
 | |
| #endif
 | |
| 
 | |
| #ifndef __REGISTER_PREFIX__
 | |
| #define __REGISTER_PREFIX__
 | |
| #endif
 | |
| 
 | |
| /* ANSI concatenation macros.  */
 | |
| 
 | |
| #define CONCAT1(a, b) CONCAT2(a, b)
 | |
| #define CONCAT2(a, b) a ## b
 | |
| 
 | |
| /* Use the right prefix for global labels.  */
 | |
| 
 | |
| #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
 | |
| 
 | |
| /* Use the right prefix for registers.  */
 | |
| 
 | |
| #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
 | |
| 
 | |
| #define d0 REG (d0)
 | |
| #define d1 REG (d1)
 | |
| #define d2 REG (d2)
 | |
| #define d3 REG (d3)
 | |
| #define d4 REG (d4)
 | |
| #define d5 REG (d5)
 | |
| #define d6 REG (d6)
 | |
| #define d7 REG (d7)
 | |
| #define a0 REG (a0)
 | |
| #define a1 REG (a1)
 | |
| #define a2 REG (a2)
 | |
| #define a3 REG (a3)
 | |
| #define a4 REG (a4)
 | |
| #define a5 REG (a5)
 | |
| #define a6 REG (a6)
 | |
| #define fp REG (fp)
 | |
| #define sp REG (sp)
 | |
| 
 | |
| /*
 | |
|  * Set up some room for a stack. We just grab a chunk of memory.
 | |
|  */
 | |
| 	.set	stack_size, 0x2000
 | |
| 	.comm	SYM (stack), stack_size
 | |
| 
 | |
| /*
 | |
|  * Define an empty environment.
 | |
|  */
 | |
|         .data
 | |
|         .align 2
 | |
| SYM (environ):
 | |
|         .long 0
 | |
| 
 | |
|  	.align	2
 | |
| 	.text
 | |
| 	.global SYM (stack)
 | |
| 
 | |
| 	.global SYM (main)
 | |
| 	.global SYM (exit)
 | |
| /* 
 | |
|  * This really should be __bss_start, not SYM (__bss_start).
 | |
|  */
 | |
| 	.global __bss_start
 | |
| 
 | |
| /*
 | |
|  * start -- set things up so the application will run.
 | |
|  */
 | |
| SYM (start):
 | |
| 	link	a6, #-8
 | |
| 	moveal	#SYM (stack) + stack_size, sp
 | |
| 
 | |
| /*
 | |
|  * zerobss -- zero out the bss section
 | |
|  */
 | |
| 	moveal	#__bss_start, a0
 | |
| 	moveal	#SYM (end), a1
 | |
| 1:
 | |
| 	movel	#0, (a0)
 | |
| 	leal	4(a0), a0
 | |
| 	cmpal	a0, a1
 | |
| 	bne	1b
 | |
| 
 | |
| /*
 | |
|  * Call the main routine from the application to get it going.
 | |
|  * main (argc, argv, environ)
 | |
|  * We pass argv as a pointer to NULL.
 | |
|  */
 | |
|         pea     0
 | |
|         pea     SYM (environ)
 | |
|         pea     sp@@(4)
 | |
|         pea     0
 | |
| 	jsr	SYM (main)
 | |
| 	movel	d0, sp@@-
 | |
| 
 | |
| /*
 | |
|  * _exit -- Exit from the application. Normally we cause a user trap
 | |
|  *          to return to the ROM monitor for another run.
 | |
|  */
 | |
| SYM (exit):
 | |
| 	trap	#0
 | |
| @end example
 | |
| 
 | |
| @node glue.c, mvme.S, crt0.S, Code Listings
 | |
| @section C based "glue" code.
 | |
| 
 | |
| @example
 | |
| 
 | |
| /*
 | |
|  * glue.c -- all the code to make GCC and the libraries run on
 | |
|  *           a bare target board. These should work with any
 | |
|  *           target if inbyte() and outbyte() exist.
 | |
|  */
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <errno.h>
 | |
| #ifndef NULL
 | |
| #define NULL 0
 | |
| #endif
 | |
| 
 | |
| /* FIXME: this is a hack till libc builds */
 | |
| __main()
 | |
| @{
 | |
|   return;
 | |
| @}
 | |
| 
 | |
| #undef errno
 | |
| int errno;
 | |
| 
 | |
| extern caddr_t _end;                /* _end is set in the linker command file */
 | |
| extern int outbyte();
 | |
| extern unsigned char inbyte();
 | |
| extern int havebyte();
 | |
| 
 | |
| /* just in case, most boards have at least some memory */
 | |
| #ifndef RAMSIZE
 | |
| #  define RAMSIZE             (caddr_t)0x100000
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * read  -- read bytes from the serial port. Ignore fd, since
 | |
|  *          we only have stdin.
 | |
|  */
 | |
| int
 | |
| read(fd, buf, nbytes)
 | |
|      int fd;
 | |
|      char *buf;
 | |
|      int nbytes;
 | |
| @{
 | |
|   int i = 0;
 | |
| 
 | |
|   for (i = 0; i < nbytes; i++) @{
 | |
|     *(buf + i) = inbyte();
 | |
|     if ((*(buf + i) == '\n') || (*(buf + i) == '\r')) @{
 | |
|       (*(buf + i)) = 0;
 | |
|       break;
 | |
|     @}
 | |
|   @}
 | |
|   return (i);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * write -- write bytes to the serial port. Ignore fd, since
 | |
|  *          stdout and stderr are the same. Since we have no filesystem,
 | |
|  *          open will only return an error.
 | |
|  */
 | |
| int
 | |
| write(fd, buf, nbytes)
 | |
|      int fd;
 | |
|      char *buf;
 | |
|      int nbytes;
 | |
| @{
 | |
|   int i;
 | |
| 
 | |
|   for (i = 0; i < nbytes; i++) @{
 | |
|     if (*(buf + i) == '\n') @{
 | |
|       outbyte ('\r');
 | |
|     @}
 | |
|     outbyte (*(buf + i));
 | |
|   @}
 | |
|   return (nbytes);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * open -- open a file descriptor. We don't have a filesystem, so
 | |
|  *         we return an error.
 | |
|  */
 | |
| int
 | |
| open(buf, flags, mode)
 | |
|      char *buf;
 | |
|      int flags;
 | |
|      int mode;
 | |
| @{
 | |
|   errno = EIO;
 | |
|   return (-1);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * close -- close a file descriptor. We don't need
 | |
|  *          to do anything, but pretend we did.
 | |
|  */
 | |
| int
 | |
| close(fd)
 | |
|      int fd;
 | |
| @{
 | |
|   return (0);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * sbrk -- changes heap size size. Get nbytes more
 | |
|  *         RAM. We just increment a pointer in what's
 | |
|  *         left of memory on the board.
 | |
|  */
 | |
| caddr_t
 | |
| sbrk(nbytes)
 | |
|      int nbytes;
 | |
| @{
 | |
|   static caddr_t heap_ptr = NULL;
 | |
|   caddr_t        base;
 | |
| 
 | |
|   if (heap_ptr == NULL) @{
 | |
|     heap_ptr = (caddr_t)&_end;
 | |
|   @}
 | |
| 
 | |
|   if ((RAMSIZE - heap_ptr) >= 0) @{
 | |
|     base = heap_ptr;
 | |
|     heap_ptr += nbytes;
 | |
|     return (base);
 | |
|   @} else @{
 | |
|     errno = ENOMEM;
 | |
|     return ((caddr_t)-1);
 | |
|   @}
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * isatty -- returns 1 if connected to a terminal device,
 | |
|  *           returns 0 if not. Since we're hooked up to a
 | |
|  *           serial port, we'll say yes and return a 1.
 | |
|  */
 | |
| int
 | |
| isatty(fd)
 | |
|      int fd;
 | |
| @{
 | |
|   return (1);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * lseek -- move read/write pointer. Since a serial port
 | |
|  *          is non-seekable, we return an error.
 | |
|  */
 | |
| off_t
 | |
| lseek(fd,  offset, whence)
 | |
|      int fd;
 | |
|      off_t offset;
 | |
|      int whence;
 | |
| @{
 | |
|   errno = ESPIPE;
 | |
|   return ((off_t)-1);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * fstat -- get status of a file. Since we have no file
 | |
|  *          system, we just return an error.
 | |
|  */
 | |
| int
 | |
| fstat(fd, buf)
 | |
|      int fd;
 | |
|      struct stat *buf;
 | |
| @{
 | |
|   errno = EIO;
 | |
|   return (-1);
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * getpid -- only one process, so just return 1.
 | |
|  */
 | |
| #define __MYPID 1
 | |
| int
 | |
| getpid()
 | |
| @{
 | |
|   return __MYPID;
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * kill -- go out via exit...
 | |
|  */
 | |
| int
 | |
| kill(pid, sig)
 | |
|      int pid;
 | |
|      int sig;
 | |
| @{
 | |
|   if(pid == __MYPID)
 | |
|     _exit(sig);
 | |
|   return 0;
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * print -- do a raw print of a string
 | |
|  */ 
 | |
| int
 | |
| print(ptr)
 | |
| char *ptr;
 | |
| @{
 | |
|   while (*ptr) @{
 | |
|     outbyte (*ptr++);
 | |
|   @}
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * putnum -- print a 32 bit number in hex
 | |
|  */
 | |
| int
 | |
| putnum (num)
 | |
| unsigned int num;
 | |
| @{
 | |
|   char  buffer[9];
 | |
|   int   count;
 | |
|   char  *bufptr = buffer;
 | |
|   int   digit;
 | |
|   
 | |
|   for (count = 7 ; count >= 0 ; count--) @{
 | |
|     digit = (num >> (count * 4)) & 0xf;
 | |
|     
 | |
|     if (digit <= 9)
 | |
|       *bufptr++ = (char) ('0' + digit);
 | |
|     else
 | |
|       *bufptr++ = (char) ('a' - 10 + digit);
 | |
|   @}
 | |
| 
 | |
|   *bufptr = (char) 0;
 | |
|   print (buffer);
 | |
|   return;
 | |
| @}
 | |
| @end example
 | |
| 
 | |
| @node mvme.S, io.c, glue.c, Code Listings
 | |
| @section I/O assembler code sample
 | |
| 
 | |
| @example
 | |
| /*
 | |
|  * mvme.S -- board support for m68k
 | |
|  */
 | |
| 
 | |
| 	.title "mvme.S for m68k-coff"
 | |
| 
 | |
| /* These are predefined by new versions of GNU cpp.  */
 | |
| 
 | |
| #ifndef __USER_LABEL_PREFIX__
 | |
| #define __USER_LABEL_PREFIX__ _
 | |
| #endif
 | |
| 
 | |
| #ifndef __REGISTER_PREFIX__
 | |
| #define __REGISTER_PREFIX__
 | |
| #endif
 | |
| 
 | |
| /* ANSI concatenation macros.  */
 | |
| 
 | |
| #define CONCAT1(a, b) CONCAT2(a, b)
 | |
| #define CONCAT2(a, b) a ## b
 | |
| 
 | |
| /* Use the right prefix for global labels.  */
 | |
| 
 | |
| #define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
 | |
| 
 | |
| /* Use the right prefix for registers.  */
 | |
| 
 | |
| #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
 | |
| 
 | |
| #define d0 REG (d0)
 | |
| #define d1 REG (d1)
 | |
| #define d2 REG (d2)
 | |
| #define d3 REG (d3)
 | |
| #define d4 REG (d4)
 | |
| #define d5 REG (d5)
 | |
| #define d6 REG (d6)
 | |
| #define d7 REG (d7)
 | |
| #define a0 REG (a0)
 | |
| #define a1 REG (a1)
 | |
| #define a2 REG (a2)
 | |
| #define a3 REG (a3)
 | |
| #define a4 REG (a4)
 | |
| #define a5 REG (a5)
 | |
| #define a6 REG (a6)
 | |
| #define fp REG (fp)
 | |
| #define sp REG (sp)
 | |
| #define vbr REG (vbr)
 | |
| 
 | |
| 	.align	2
 | |
| 	.text
 | |
| 	.global SYM (_exit)
 | |
| 	.global SYM (outln)
 | |
| 	.global SYM (outbyte)
 | |
| 	.global SYM (putDebugChar)
 | |
| 	.global SYM (inbyte)
 | |
| 	.global SYM (getDebugChar)
 | |
| 	.global SYM (havebyte)
 | |
| 	.global SYM (exceptionHandler)
 | |
| 
 | |
| 	.set	vbr_size, 0x400
 | |
| 	.comm	SYM (vbr_table), vbr_size
 | |
| 
 | |
| /*
 | |
|  * inbyte -- get a byte from the serial port
 | |
|  *	d0 - contains the byte read in
 | |
|  */
 | |
| 	.align	2
 | |
| SYM (getDebugChar):		/* symbol name used by m68k-stub */
 | |
| SYM (inbyte):
 | |
| 	link	a6, #-8
 | |
| 	trap 	#15
 | |
| 	.word	inchr
 | |
| 	moveb 	sp@@, d0
 | |
| 	extbl	d0
 | |
| 	unlk	a6
 | |
| 	rts
 | |
| 
 | |
| /*
 | |
|  * outbyte -- sends a byte out the serial port
 | |
|  *	d0 - contains the byte to be sent
 | |
|  */
 | |
| 	.align	2
 | |
| SYM (putDebugChar):		/* symbol name used by m68k-stub */
 | |
| SYM (outbyte):
 | |
| 	link	fp, #-4
 | |
|  	moveb	fp@@(11), sp@@
 | |
| 	trap 	#15
 | |
| 	.word	outchr
 | |
| 	unlk	fp
 | |
| 	rts
 | |
| 
 | |
| /*
 | |
|  * outln -- sends a string of bytes out the serial port with a CR/LF
 | |
|  *	a0 - contains the address of the string's first byte
 | |
|  *	a1 - contains the address of the string's last byte
 | |
|  */
 | |
| 	.align	2
 | |
| SYM (outln):
 | |
| 	link	a6, #-8
 | |
| 	moveml	a0/a1, sp@@
 | |
| 	trap 	#15
 | |
| 	.word 	outln
 | |
| 	unlk	a6
 | |
| 	rts
 | |
| 
 | |
| /*
 | |
|  * outstr -- sends a string of bytes out the serial port without a CR/LF
 | |
|  *	a0 - contains the address of the string's first byte
 | |
|  *	a1 - contains the address of the string's last byte
 | |
|  */
 | |
| 	.align	2
 | |
| SYM (outstr):
 | |
| 	link	a6, #-8
 | |
| 	moveml	a0/a1, sp@@
 | |
| 	trap 	#15
 | |
| 	.word 	outstr
 | |
| 	unlk	a6
 | |
| 	rts
 | |
| 
 | |
| /*
 | |
|  * havebyte -- checks to see if there is a byte in the serial port,
 | |
|  *	     returns 1 if there is a byte, 0 otherwise.
 | |
|  */
 | |
| SYM (havebyte):
 | |
| 	trap 	#15
 | |
| 	.word	instat
 | |
| 	beqs	empty
 | |
| 	movel 	#1, d0
 | |
| 	rts
 | |
| empty:
 | |
| 	movel	#0, d0
 | |
| 	rts
 | |
| 
 | |
| /*
 | |
|  * These constants are for the MVME-135 board's boot monitor. They
 | |
|  * are used with a TRAP #15 call to access the monitor's I/O routines.
 | |
|  * they must be in the word following the trap call.
 | |
|  */
 | |
| 	.set inchr, 0x0
 | |
| 	.set instat, 0x1
 | |
| 	.set inln, 0x2
 | |
| 	.set readstr, 0x3
 | |
| 	.set readln, 0x4
 | |
| 	.set chkbrk, 0x5
 | |
| 
 | |
| 	.set outchr, 0x20
 | |
| 	.set outstr, 0x21
 | |
| 	.set outln, 0x22
 | |
| 	.set write, 0x23
 | |
| 	.set writeln, 0x24
 | |
| 	.set writdln, 0x25
 | |
| 	.set pcrlf, 0x26
 | |
| 	.set eraseln, 0x27
 | |
| 	.set writd, 0x28
 | |
| 	.set sndbrk, 0x29
 | |
| 
 | |
| 	.set tm_ini, 0x40
 | |
| 	.set dt_ini, 0x42
 | |
| 	.set tm_disp, 0x43
 | |
| 	.set tm_rd, 0x44
 | |
| 
 | |
| 	.set redir, 0x60
 | |
| 	.set redir_i, 0x61
 | |
| 	.set redir_o, 0x62
 | |
| 	.set return, 0x63
 | |
| 	.set bindec, 0x64
 | |
| 
 | |
| 	.set changev, 0x67
 | |
| 	.set strcmp, 0x68
 | |
| 	.set mulu32, 0x69
 | |
| 	.set divu32, 0x6A
 | |
| 	.set chk_sum, 0x6B
 | |
| 
 | |
| @end example
 | |
| 
 | |
| @node io.c, leds.c, mvme.S, Code Listings
 | |
| @section I/O code sample
 | |
| 
 | |
| @example
 | |
| #include "w89k.h"
 | |
| 
 | |
| /*
 | |
|  * outbyte -- shove a byte out the serial port. We wait till the byte 
 | |
|  */
 | |
| int
 | |
| outbyte(byte)
 | |
|      unsigned char byte;
 | |
| @{
 | |
|   while ((inp(RS232REG) & TRANSMIT) == 0x0) @{  @} ;
 | |
|   return (outp(RS232PORT, byte));
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * inbyte -- get a byte from the serial port
 | |
|  */
 | |
| unsigned char
 | |
| inbyte()
 | |
| @{
 | |
|   while ((inp(RS232REG) & RECEIVE) == 0x0) @{ @};
 | |
|   return (inp(RS232PORT));
 | |
| @}
 | |
| @end example
 | |
| 
 | |
| @node leds.c, ,io.c, Code Listings
 | |
| @section Led control sample
 | |
| 
 | |
| @example
 | |
| /*
 | |
|  * leds.h -- control the led's on a Motorola mc68ec0x0 board.
 | |
|  */
 | |
| 
 | |
| #ifndef __LEDS_H__
 | |
| #define __LEDS_H__
 | |
| 
 | |
| #define LED_ADDR	0xd00003
 | |
| #define LED_0           ~0x1
 | |
| #define LED_1           ~0x2
 | |
| #define LED_2           ~0x4
 | |
| #define LED_3           ~0x8
 | |
| #define LED_4           ~0x10
 | |
| #define LED_5           ~0x20
 | |
| #define LED_6           ~0x40
 | |
| #define LED_7           ~0x80
 | |
| #define LEDS_OFF	0xff
 | |
| #define LEDS_ON		0x0
 | |
| 
 | |
| #define FUDGE(x) ((x >= 0xa && x <= 0xf) ? (x + 'a') & 0x7f : (x + '0') & 0x7f)
 | |
| 
 | |
| extern void led_putnum( char );
 | |
| 
 | |
| #endif		/* __LEDS_H__ */
 | |
| 
 | |
| /*
 | |
|  * leds.c -- control the led's on a Motorola mc68ec0x0 (IDP)board.
 | |
|  */
 | |
| #include "leds.h"
 | |
| 
 | |
| void zylons();
 | |
| void led_putnum();
 | |
| 
 | |
| /*
 | |
|  * led_putnum -- print a hex number on the LED. the value of num must be a char with
 | |
|  *              the ascii value. ie... number 0 is '0', a is 'a', ' ' (null) clears
 | |
|  *		the led display.
 | |
|  *		Setting the bit to 0 turns it on, 1 turns it off.
 | |
|  * 		the LED's are controlled by setting the right bit mask in the base
 | |
|  * 		address. 
 | |
|  *		The bits are:
 | |
|  *			[d.p | g | f | e | d | c | b | a ] is the byte.
 | |
|  *
 | |
|  *		The locations are:
 | |
|  *		
 | |
|  *			 a
 | |
|  *		       -----
 | |
|  *		    f |     | b
 | |
|  *		      |  g  |
 | |
|  *		       -----
 | |
|  *                    |     |
 | |
|  *                  e |     | c
 | |
|  *                     -----
 | |
|  *                       d                . d.p (decimal point)
 | |
|  */
 | |
| void
 | |
| led_putnum ( num )
 | |
| char num;
 | |
| @{
 | |
|     static unsigned char *leds = (unsigned char *)LED_ADDR;
 | |
|     static unsigned char num_bits [18] = @{
 | |
|       0xff,						/* clear all */
 | |
|       0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, /* numbers 0-9 */
 | |
|       0x98, 0x20, 0x3, 0x27, 0x21, 0x4, 0xe 		/* letters a-f */
 | |
|     @};
 | |
| 
 | |
|     if (num >= '0' && num <= '9')
 | |
|       num = (num - '0') + 1;
 | |
| 
 | |
|     if (num >= 'a' && num <= 'f')
 | |
|       num = (num - 'a') + 12;
 | |
| 
 | |
|     if (num == ' ')
 | |
|       num = 0;
 | |
| 
 | |
|     *leds = num_bits[num];
 | |
| @}
 | |
| 
 | |
| /*
 | |
|  * zylons -- draw a rotating pattern. NOTE: this function never returns.
 | |
|  */
 | |
| void
 | |
| zylons()
 | |
| @{
 | |
|   unsigned char *leds 	= (unsigned char *)LED_ADDR;
 | |
|   unsigned char curled = 0xfe;
 | |
| 
 | |
|   while (1)
 | |
|     @{
 | |
|       *leds = curled;
 | |
|       curled = (curled >> 1) | (curled << 7);
 | |
|       delay ( 200 );
 | |
|     @}
 | |
| @}
 | |
| @end example
 | |
| 
 | |
| @page
 | |
| @contents
 | |
| @c second page break makes sure right-left page alignment works right
 | |
| @c with a one-page toc, even though we don't have setchapternewpage odd.
 | |
| @page
 | |
| @bye
 |