| \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 |