Name
HAL Port — Implementation Details
Description
This documentation explains how the eCos HAL specification has been mapped onto H8/300 hardware, and should be read in conjunction with that specification. It also describes how variant, processor and platform HALs can modify the default behaviour.
eCos support for any given target will involve either three or four HAL packages: the architectural HAL, the platform HAL, the variant HAL, and optionally a processor HAL. This package, the architectural HAL, provides code and definitions that are applicable to all H8/300 processors. The platform HAL provides support for one specific board, or possibly for a number of almost-identical boards. The processor HAL, if present, serves mainly to provide details of on-chip peripherals including the interrupt controller. The variant HAL provides functionality that is common to a group of processors, for example all H8S processors have very similar UARTs and hence can share HAL diagnostic code. There is no fixed specification of what should go into the variant HAL versus the processor HAL. For simplicity the description below only refers to variant HALs, but the work may actually happen in a processor HAL instead.
As a design goal lower-level HALs can always override functionality
that is normally provided higher up. For example the architectural HAL
will provide the required eCos HAL_LSBIT_INDEX
and HAL_MSBIT_INDEX
macros, but these can be
provided lower down instead. In some areas such as handling context
switching the architectural HAL will usually provide the basic
functionality but it may be extended by lower HALs. The architecture
HAL consequently contains a large number of macros at both C and
assembler level that variant HALs are expected to supply functionality
for.
The architectural HAL provides header files cyg/hal/hal_arch.h
, cyg/hal/hal_intr.h
, cyg/hal/hal_cache.h
, cyg/hal/hal_io.h
and cyg/hal/arch.inc
. These automatically
include an equivalent header file from the variant HAL, for example
cyg/hal/var_arch.h
. The
variant HAL header will in turn include processor and
platform-specific headers. This means that application developers and
other packages can simply include the architectural HAL headers
without needing to know about variants or platforms. It also allows
the variant and platform HALs to override architectural settings.
Data Types
For eCos purposes all H8/300 processors are big-endian and 32-bit, so
the default data types in cyg/infra/cyg_type.h
are used. Some
variants have external bus widths less than 32-bit, but this does not
affect the architectural HAL.
Startup and Exception Vectors
The conventional bootstrap mechanism involves a table of exception vectors at the base of memory. The first two words of this table are reset entry points for power-on reset and manual reset. In a typical embedded system the hardware is arranged such that non-volatile flash memory is found at location 0x0 so it is the start of flash that contains the exception vectors and the boot code. The table of exception vectors is used subsequently for interrupt handling and for hardware exceptions.
The exact hardware details, the various startup types, the steps
needed for low-level hardware initialization, and so on are not known
to the architectural HAL. Hence although the architectural HAL does
provide the basic framework for startup, much of the work is done via
macros provided by lower-level HAL packages and those macros are
likely to depend on various configuration options. Rather than try to
enumerate all the various combinations here it is better to look at
the actual code in vectors.S
and in appropriate
variant, processor or platform HALs. vectors.S
is
responsible for any low-level initialization that needs to happen.
This includes setting up a standard C environment with the stack
pointer set to the startup stack in working RAM, making sure all
statically initialized global variables have the correct values, and
that all uninitialized global variables are zeroed. Once the C
environment has been set up the code jumps to
cyg_start()
which completes the initialization
and jumps to the application entry point.
Interrupt Handling
The H8/300 architecture reserves a vector table area of memory for exception vectors. These are used for internal and external interrupts, exceptions, software traps, and special operations such as reset handling. Some of the vectors have well-defined uses. However when it comes to interrupt handling the details will depend on the processor variant and on the platform, and the appropriate package documentation should be consulted for full details.
The default behaviour is for all exceptions and interrupts to be
vectored from the hardware vector table via the JSR
hook table to a piece of trampoline code. This saves the CPU state on
the stack and decodes the hook table return address into a simple
vector number. This is then used to index the VSR table and fetch the
address of the Vector Service Routine for that exception. This is then
called with the vector number in ER1.
The standard eCos macros HAL_VSR_GET
and
HAL_VSR_SET
just manipulate one of the
entries in the VSR table. Hence it is possible to
replace the default handlers for exceptions and traps in addition to
interrupt handlers. hal_intr.h
provides #define
's for the more common exception
vectors, and additional ones can be provided by the platform or
variant. It is the responsibility of the platform or variant HAL to
initialize the table, and to provide the
HAL_VSR_SET_TO_ECOS_HANDLER
macro since that
requires knowledge of the default table entries.
At the architecture level there is no fixed mapping between VSR and
ISR vectors. Instead that is left to the variant or platform HAL. The
architectural HAL does provide default implementations of
HAL_INTERRUPT_ATTACH
,
HAL_INTERRUPT_DETACH
and
HAL_INTERRUPT_IN_USE
since these just involve
updating a static table.
By default the interrupt state control macros
HAL_DISABLE_INTERRUPTS
,
HAL_RESTORE_INTERRUPTS
,
HAL_ENABLE_INTERRUPTS
and
HAL_QUERY_INTERRUPTS
are implemented by the
variant HAL for the different processor variants, and involve updating
either the condition code or extended control registers.
HAL_DISABLE_INTERRUPTS
has no effect on
non-maskable interrupts. This causes a problem because parts of the
system assume that all normal interrupt sources are affected by this
macro. If the target hardware can raise non-maskable interrupts then
it is the responsibility of application code to install a suitable VSR
and handle non-maskable interrupts entirely within the application,
bypassing the usual eCos ISR and DSR mechanisms.
The architectural HAL does not provide any support for the interrupt
controller management macros like
HAL_INTERRUPT_MASK
. These can only be implemented
on a per-variant, per-processor or per-platform basis.
Exception Handling
Synchronous exception handling is done in much the same way as interrupt handling.
The details of exception handling vary from one variant to the next depending on the interrupt control mode. The architectural HAL makes no attempt to cope with these differences, and it is the responsibility of the variants to provide more advanced support. Otherwise if an exception needs to be handled in a very specific way then it is up to the application to install a suitable VSR and handle the exception directly.
Stacks and Stack Sizes
cyg/hal/hal_arch.h
defines
values for minimal and recommended thread stack sizes,
CYGNUM_HAL_STACK_SIZE_MINIMUM
and
CYGNUM_HAL_STACK_SIZE_TYPICAL
. These values are
specific to the current configuration, and are affected mainly by
options related to interrupt handling.
By default eCos uses a separate interrupt stack, although this can be
disabled through the configuration option
CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
.
When an interrupt or exception occurs eCos will save the context on
the current stack and then switch to the interrupt stack before
calling the appropriate ISR interrupt handler. This means that thread
stacks can be significantly smaller because there is no need to worry
about interrupt handling overheads, just the thread context. However
switching the stack does require some extra work and hence increases
the interrupt latency. Disabling the interrupt stack removes this
processing overhead but requires larger stack sizes. It depends on
the application whether or not this is a sensible trade off.
By default eCos does not allow nested interrupts, but this can be
controlled via the configuration option
CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
.
Supporting nested interrupts requires larger thread stacks, especially
if the separate interrupt stack is also disabled. It may also require
additional support from the variant and platform HALs. Note that at
present this support is not complete in any variant, so interrupt
nesting is currently disabled.
The H8/300 is somewhat register-poor, and although the calling conventions are register-oriented, a lot of use is made of stack space. In particular register contents must be spilled to the stack frequently, and the return address is pushed rather than ending up in a link register. To allow for this the recommended minimum stack sizes are a little bit larger than for some other architectures. Variant HALs cannot directly affect these stack sizes.
Usually the H8/300 architectural HAL will provide a single block of memory which acts as both the startup and interrupt stack, and there are configuration options to control the size of this block.
Thread Contexts and Setjmp/Longjmp
A typical thread context consists of the following:
The integer context. This consists of the data registers
ER0
toER6
. The stack pointer registerER7
does not have to be always saved explicitly since it is implicit in the pointer to the saved context.The caller-save registers are
ER0
toER2
, and the condition code register. The remaining registers are callee-save. The result is passed back viaER0
.-
The condition code
register, the program counter, and extended status register
EXR
on H8S. These are special because when an interrupt occurs the hardware automatically pushes these onto the stack, but exactly what gets pushed depends on the variant.
setjmp
and longjmp
only deal
with the callee-save registers.
The variant HAL package can override the default implementations if
necessary.
When porting to a new H8/300 variant, the variant HAL must define a number of assembler-level macros to customize the behaviour of the architecture HAL to the variant. These are too numerous to specify in detail here and the reader is directed to look at the existing HAL ports for examples.
Bit Indexing
For performance reasons the HAL_LSBIT_INDEX
and
HAL_MSBIT_INDEX
macros are implemented using
functions containing inline assembler. A variant HAL can override the
default definitions if, for example, the variant has special
instructions to perform these operations.
Idle Thread Processing
The default HAL_IDLE_THREAD_ACTION
implementation
is a no-op. A variant HAL may override this, for example to put the
processor into sleep mode. Alternative implementations should consider
exactly how this macro gets used in eCos kernel code.
Clock Support
The architectural HAL cannot provide the required clock support because it does not know what timer hardware may be available on the target hardware. Instead this is left to either the variant or platform HAL, depending on whether the processor has a suitable on-chip timer or whether an off-chip timer has to be used.
HAL I/O
The H8/300 architecture does not have a separate I/O bus. Instead all hardware is assumed to be memory-mapped. Further it is assumed that all peripherals on the memory bus are wired appropriately for a big-endian processor and that there is no need for any byte swapping. Hence the various HAL macros for performing I/O simply involve pointers to volatile memory.
The variant, processor and platform equivalents of the cyg/hal/hal_io.h
header will typically
also provide details of some or all of the peripherals, for example
register offsets and the meaning of various bits in those registers.
Diagnostic Support
The architecture HAL provides an implementation of the SCI serial
device that is common to all H8/300 microcontrollers. However, it is
the responsibility of the the variant or platform HAL to provide the
register definitions and to instantiate the devices by calling
cyg_hal_plf_sci_init()
.
SMP Support
The H8/300 port does not have SMP support.
Debug Support
The H8300 architectural HAL package provides basic support only for gdb stubs. There is no support for more advanced debug features like hardware watchpoints. Trace-based single step is supported on the H8S variant.
Other Functionality
The H8/300 architectural HAL only implements the functionality provided by the eCos HAL specification and does not export any extra functionality.
2024-03-18 | eCosPro Non-Commercial Public License |