eCos Product

eCos Net Distribution


RedBoot Product
 
RedBoot Net Distribution


Supported Hardware

Downloading and Installation

Documentation

FAQ

Keeping in Touch

Problems

Licensing

Anonymous CVS

Contributions and Third Party Projects

Red Hat eCos

HAL Platform Porting Process


Brief overview

The easiest way to make a new platform HAL is simply to copy an existing platform HAL of the same architecture and change all the files to match the new platform. In case this is the first platform for the architecture, a platform HAL from another architecture should be used as a template.

The first goal of a HAL port is the creation of a minimal GDB eCos stub which can be put in flash or ROM on the board to provide simple "load and go" functionality. This allows further HAL development to happen using RAM startup configurations, which is desirable for the simple reason that downloading an image which you need to test is often many times faster than either updating a flash part, or indeed, erasing and reprogramming an EPROM.

There are two approaches to getting to this first goal:

  1. The board is equipped with a ROM monitor which allows "load and go" of ELF, binary or some other image type which can be created using objcopy. This allows you to develop the "load and go" GDB stub by downloading and running the code (saving time).

    When the stub is running it is a good idea to examine the various hardware registers to help you write the platform initialization code.

    Then you may have to fiddle a bit going through step two (getting it to run from ROM startup). If at all possible, preserve the original ROM monitor so you can revert to it if necessary.

  2. The board has no ROM monitor (or you have the stub working for RAM startup). You need to get the platform initialization and stub working by repeatedly making changes, updating flash or EPROM and testing the changes. If you are lucky, you have a JTAG or similar CPU debugger to help you. If not, you will probably learn to appreciate LEDs.

Step-by-step

Given that no two platforms are exactly the same, you may have to deviate from the below. Also, you should expect a fair amount of fiddling - things almost never go right the first time. See the hints section below for some suggestions that might help debugging.

The below descriptions are based on the HAL layout used in the MIPS and MN10300 HALs. Eventually all HALs should be converted to look like these - but in a transition period there will be other HALs which look substantially different. Please try to adhere to the below as much is possible without causing yourself too much grief integrating with a HAL which does not follow this layout. [FIXME: ref layout]

Minimal requirements
These are the changes you must make before you attempt to build the eCos GDB stub. You are advised to read all the sources though.
  1. Copy an existing platform HAL from the same or another architecture. Rename the files as necessary to follow the standard: CDL and MLT related files should contain the <arch>_<variant>_<platform> tripplet.

  2. Adjust CDL options. Primarily option naming, real-time clock/counter, and CYGHWR_MEMORY_LAYOUT variables, but also other options may need editing. Look through the architecture/variant CDL files to see if there are any requirements/features which where not used on the platform you copied. If so, add appropriate ones.

  3. Add the necessary packages and target descriptions to the top-level ecos.db file.

  4. Adjust the MLT files in include/pkgconf to match the memory layout on the platform. For initial testing it should be enough to just hand edit .h and .ldi files, but eventually you should generate all files using the memory layout editor in the configuration tool.

  5. If the default IO macros are not correct, override them in plf_io.h. This may be necessary if the platform uses a different endianess from what is default for the CPU.

  6. Leave out/comment out code that enables caches and/or MMU if possible. Execution speed will not be a concern until the port is feature complete.

  7. Implement a simple serial driver (polled mode only). Make sure the initialization function properly hooks the procedures up in the virtual vector IO channel tables. The stub will call the serial driver via these tables.

  8. Adjust/implement necessary platform initialization. This can be found in platform.inc and platform.S files (ARM: hal_platform_setup.h and <platform>_misc.c, PowerPC: <platform>.S, FIXME). This step can be postponed if you are doing RAM startup stubs first and the existing ROM monitor handles board initialization.

  9. Define HAL_STUB_PLATFORM_RESET (optionally empty) and HAL_STUB_PLATFORM_RESET_ENTRY so the minimal stub can reset-on-detach - this is very handy, often removing the need for physically resetting the board between downloads.

You should now be able to build some simple stubs. For ROM startup:

% ecosconfig new <target_name> stubs
% ecosconfig remove CYGPKG_IO
% ecosconfig remove CYGPKG_IO_SERIAL
% ecosconfig remove CYGPKG_ERROR
[possibly remove other driver packages which are not needed by the stub]

Now edit ecos.ecc, disabling CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT, CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT, and CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT.

For RAM startup, also change the CYG_HAL_STARTUP option to RAM.

% ecosconfig tree
% make

You may have to make further changes than suggested above to get the make command to succeed. But when it does, you should find a stub image in install/bin. To program this image into flash or EPROM, you may need to convert to some other file type, and possibly adjust the start address. When you have the correct objcopy command to do this, add it to the CYGBLD_BUILD_GDB_STUBS custom build rule in the platform CDL file.

Having updated the flash/EPROM on the board, you should see output on the serial port looking like the below when powering on the board:

$T0540:fff05cd8;01:00004664;#92

If you do not see this output, you need to go through all your changes and figure out what's wrong. If there's a user programmable LED on the board it may help you figure out how far the stub gets before it hangs. Unfortunately there's no good way to describe what to do in this situation - other than that you have to play with the code and the board.

Adding features

Now you should have a simple "load and go" eCos GDB stub running on the board. This means you have a the correct board initialization and a working serial driver. It's time to flesh out the remaining stub and HAL features.

  1. Stub reset. As mentioned above it is desirable to get the board to reset when GDB disconnects. When GDB disconnects it sends the stub a kill-packet, and the stub first calls HAL_STUB_PLATFORM_RESET, attempting to perform a software-invoked reset. Most embedded CPUs/boards have a watchdog which is capable of triggering a reset. If your target does not have a watchdog, leave HAL_STUB_PLATFORM_RESET empty and rely on the fallback approach.

    If HAL_STUB_PLATFORM_RESET did not cause a reset, the stub will jump to HAL_STUB_PLATFORM_RESET_ENTRY - this should be the address where the CPU will start execution after a reset. Re-initializing the board and drivers will usually be good enough to make a hardware reset unnecessary.

    After the reset caused by the kill-packet, the target will be ready for GDB to connect again. During a days work, this will save you from pressing the reset button many times.

    Note that it is possible to disconnect from the board without causing it to reset by using the GDB command 'detach'.

  2. Single-stepping is necessary for both instruction-level debugging and for breakpoint support. Single-stepping support should already be in place as part of the architecture/variant HAL, but you want to give it a quick test since you will come to rely on it.

  3. Real-time clock interrupts drive the eCos scheduler clock. Many embedded CPUs have an on-core timer (e.g. SH) or decrementer (e.g. MIPS, PPC) that can be used, and in this case it will already be supported by the architecture/variant HAL. You only have to calculate and enter the proper CYGNUM_HAL_RTC_CONSTANTS definitions in the platform CDL file.

    On some targets it may be necessary to use a platform-specific timer source for driving the real-time clock. In this case you also have to enter the proper CDL definitions, but must also define suitable versions of the HAL_CLOCK_xx macros.

  4. Interrupt decoding usually differs between platforms because the amount and type of devices on the board differ. In plf_intr.h you must either extend or replace the vector definitions otherwise provided by the architecture or variant interrupt headers. You may also have to define HAL_INTERRUPT_xxx control macros.

  5. Caching may also differ from architecture/variant definitions. Maybe just the sizes, but it can also be bigger differences for example if the platform supports 2nd level caches.

    When cache definitions are in place, enable the caches on startup. First verify that the system is stable for RAM startups, then build a new stub and install it. This will test if caching, and in particular the cache sync/flush operations, also work for ROM startup.

  6. Asynchronous breakpoints allow you to stop application execution and enter the debugger. Asynchronous breakpoint details are described here.

You should now have a completed platform HAL port. Verify its stability and completeness by running all the eCos tests and fix any problems that show up (you have a working stub now, remember?! That means you can debug the code to see why it fails).

Given the many configuration options in eCos, there may be hidden bugs or missing features which do not show up even if you run all the tests succesfully with a default configuration. A comprehensive test of the entire system will take many configuration permutations and many many thousands of tests executed. [FIXME: ref something about testing?!?]

Hints

  • JTAG or similar CPU debugging hardware can greatly reduce the time it takes to write a HAL port since you always have full visibility of what the CPU is doing.

  • LEDs can be your friends if you don't have a JTAG device. Especially in the start of the porting effort if you don't already have a working ROM monitor on the target. Then you have to get a basic stub working while basically being blindfolded. The LED can make it little easier, as you'll be able to do limited tracking of program flow and behavior by switching the LED on and off. If the board has multiple LEDs you can show a number (using binary notation with the LEDs) ans sprinkle code which sets different numbers throughout the code.

  • Debugging the interrupt processing is possible if you are careful with the way you program the very early interrupt entry handling. Write it so that as soon as possible in the interrupt path, taking a trap (exception) does no harm execution. See the SH vectors.S code for an example. Look for cyg_hal_default_interrupt_vsr and the label cyg_hal_default_interrupt_vsr_bp_safe, which marks the point after which traps/single-stepping is safe.

    Being able to display memory content, CPU registers, interrupt controller details at the time of an interrupt can save a lot of time.

  • Using assertions is a good idea. They can sometimes reveal subtle bugs or missing features long before you would otherwise have found them, let alone notice them.

    The default eCos configuration does not use assertions, so you have to enable them by switching on the option CYGPKG_INFRA_DEBUG in the infra package.

  • The idle loop can be used to help debug the system.

    Triggering clock from the idle loop is a neat trick for examining system behavior either before interrupts are fully working, or to speed up "the clock".

    Use the idle loop to monitor and/or print out variables or hardware registers.

  • hal_mk_defs is used in some of the HALs (ARM, SH) as a way to generate assembler symbol definitions from C header files without imposing an assembler/C syntax separation in the C header files.

  • Tracing using buffers [FIXME:TBD]