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
|
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:
- 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.
- 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.
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.
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.
Add the necessary packages and target descriptions to the
top-level ecos.db file.
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.
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.
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.
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.
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.
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.
- 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'.
- 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.
- 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.
- 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.
- 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.
- 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]
|