|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The eCos Hardware Abstraction Layer (HAL)
|
The eCos Hardware Abstraction Layer (HAL)
|
|
|
|
|
|
|
|
|
Introduction
|
Introduction
|
|
|
This is an initial specification of the eCos Hardware Abstraction Layer (HAL). The HAL abstracts
|
-->Hardware Abstraction Layer (HAL). The HAL abstracts
|
the underlying hardware of a processor architecture and/or the
|
the underlying hardware of a processor architecture and/or the
|
platform to a level sufficient for the eCos kernel to be ported onto
|
platform to a level sufficient for the eCos kernel to be ported onto
|
that platform.
|
that platform.
|
|
|
|
|
|
|
Caveat
|
Caveat
|
|
|
This document is an informal description of the HAL capabilities and
|
This document is an informal description of the HAL capabilities and
|
is not intended to be full documentation, although it may be used as a
|
is not intended to be full documentation, although it may be used as a
|
source for such. It also describes the HAL as it is currently
|
source for such. It also describes the HAL as it is currently
|
implemented for the architectures targeted in this release. It most
|
implemented for the architectures targeted in this release. It most
|
closely describes the HALs for the MIPS, I386 and PowerPC HALs. Other
|
closely describes the HALs for the MIPS, I386 and PowerPC HALs. Other
|
architectures are similar but may not be organized precisely as
|
architectures are similar but may not be organized precisely as
|
described here.
|
described here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Architecture, Variant and Platform
|
Architecture, Variant and Platform
|
|
|
|
|
We have identified three levels at which the HAL must operate.
|
We have identified three levels at which the HAL must operate.
|
|
|
|
|
|
|
|
|
|
|
The architecture
|
The architecture
|
HAL abstracts the basic CPU architecture and includes
|
HAL abstracts the basic CPU architecture and includes
|
things like interrupt delivery, context switching, CPU startup
|
things like interrupt delivery, context switching, CPU startup
|
etc.
|
etc.
|
|
|
|
|
|
|
|
|
|
|
The variant HAL
|
The variant HAL
|
encapsulates features of the CPU variant such as caches, MMU and
|
encapsulates features of the CPU variant such as caches, MMU and
|
FPU features. It also deals with any on-chip peripherals such as
|
FPU features. It also deals with any on-chip peripherals such as
|
memory and interrupt controllers. For architectural variations,
|
memory and interrupt controllers. For architectural variations,
|
the actual implementation of the variation is often in the
|
the actual implementation of the variation is often in the
|
architectural HAL, and the variant HAL simply provides the correct
|
architectural HAL, and the variant HAL simply provides the correct
|
configuration definitions.
|
configuration definitions.
|
|
|
|
|
|
|
|
|
|
|
The platform HAL
|
The platform HAL
|
abstracts the properties of the current platform and includes
|
abstracts the properties of the current platform and includes
|
things like platform startup, timer devices, I/O register access
|
things like platform startup, timer devices, I/O register access
|
and interrupt controllers.
|
and interrupt controllers.
|
|
|
|
|
|
|
|
|
|
|
|
|
The boundaries between these three HAL levels are necessarily blurred
|
The boundaries between these three HAL levels are necessarily blurred
|
since functionality shifts between levels on a target-by-target basis.
|
since functionality shifts between levels on a target-by-target basis.
|
For example caches and MMU may be either an architecture feature or a
|
For example caches and MMU may be either an architecture feature or a
|
variant feature. Similarly, memory and interrupt controllers may be
|
variant feature. Similarly, memory and interrupt controllers may be
|
on-chip and in the variant HAL, or off-chip and in the platform HAL.
|
on-chip and in the variant HAL, or off-chip and in the platform HAL.
|
|
|
|
|
Generally there is a separate package for each of the architecture,
|
Generally there is a separate package for each of the architecture,
|
variant and package HALs for a target. For some of the older targets,
|
variant and package HALs for a target. For some of the older targets,
|
or where it would be essentially empty, the variant HAL is omitted.
|
or where it would be essentially empty, the variant HAL is omitted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
General principles
|
General principles
|
|
|
|
|
The HAL has been implemented according to the following general
|
The HAL has been implemented according to the following general
|
principles:
|
principles:
|
|
|
|
|
|
|
The HAL is implemented in C and assembler, although the
|
The HAL is implemented in C and assembler, although the
|
eCos kernel is largely implemented in C++.
|
eCos kernel is largely implemented in C++.
|
This is to permit the HAL the widest possible
|
This is to permit the HAL the widest possible
|
applicability.
|
applicability.
|
|
|
|
|
All interfaces to the HAL are implemented by
|
All interfaces to the HAL are implemented by
|
CPP macros. This allows them to be implemented as inline
|
CPP macros. This allows them to be implemented as inline
|
C code, inline assembler or function calls to external C
|
C code, inline assembler or function calls to external C
|
or assembler code. This allows the most efficient
|
or assembler code. This allows the most efficient
|
implementation to be selected without affecting the
|
implementation to be selected without affecting the
|
interface. It also allows them to be redefined if the
|
interface. It also allows them to be redefined if the
|
platform or variant HAL needs to replace or enhance a definition
|
platform or variant HAL needs to replace or enhance a definition
|
from the architecture HAL.
|
from the architecture HAL.
|
|
|
|
|
The HAL provides simple, portable mechanisms for dealing
|
The HAL provides simple, portable mechanisms for dealing
|
with the hardware of a wide range of architectures and platforms.
|
with the hardware of a wide range of architectures and platforms.
|
It is always possible to bypass the HAL and program the hardware
|
It is always possible to bypass the HAL and program the hardware
|
directly, but this may lead to a loss of portability.
|
directly, but this may lead to a loss of portability.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL Interfaces
|
HAL Interfaces
|
|
|
|
|
This section describes the main HAL interfaces.
|
This section describes the main HAL interfaces.
|
|
|
|
|
|
|
|
|
|
|
Base Definitions
|
Base Definitions
|
|
|
|
|
These are definitions that characterize the properties of the base
|
These are definitions that characterize the properties of the base
|
architecture that are used to compile the portable parts of the
|
architecture that are used to compile the portable parts of the
|
kernel. They are concerned with such things a portable type
|
kernel. They are concerned with such things a portable type
|
definitions, endianness, and labeling.
|
definitions, endianness, and labeling.
|
|
|
|
|
|
|
These definitions are supplied by the
|
These definitions are supplied by the
|
cyg/hal/basetype.h header file which is supplied
|
cyg/hal/basetype.h header file which is supplied
|
by the architecture HAL. It is included automatically by
|
by the architecture HAL. It is included automatically by
|
cyg/infra/cyg_type.h.
|
cyg/infra/cyg_type.h.
|
|
|
|
|
|
|
|
|
|
|
Byte order
|
Byte order
|
|
|
|
|
CYG_BYTEORDER
|
CYG_BYTEORDER
|
|
|
|
|
This defines the byte order of the target and must be set to either
|
This defines the byte order of the target and must be set to either
|
CYG_LSBFIRST or CYG_MSBFIRST.
|
CYG_LSBFIRST or CYG_MSBFIRST.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Label Translation
|
Label Translation
|
|
|
|
|
|
|
CYG_LABEL_NAME(name)
|
CYG_LABEL_NAME(name)
|
|
|
|
|
|
|
This is a wrapper used in some C and C++ files which
|
This is a wrapper used in some C and C++ files which
|
use labels defined in assembly code or the linker script.
|
use labels defined in assembly code or the linker script.
|
It need only be defined if the default implementation in
|
It need only be defined if the default implementation in
|
cyg/infra/cyg_type.h, which passes the name
|
cyg/infra/cyg_type.h, which passes the name
|
argument unaltered, is inadequate. It should be paired with
|
argument unaltered, is inadequate. It should be paired with
|
CYG_LABEL_DEFN().
|
CYG_LABEL_DEFN().
|
|
|
|
|
|
|
|
|
CYG_LABEL_DEFN(name)
|
CYG_LABEL_DEFN(name)
|
|
|
|
|
|
|
This is a wrapper used in assembler sources and linker scripts
|
This is a wrapper used in assembler sources and linker scripts
|
which define labels. It need only be defined if the default
|
which define labels. It need only be defined if the default
|
implementation in
|
implementation in
|
cyg/infra/cyg_type.h, which passes the name
|
cyg/infra/cyg_type.h, which passes the name
|
argument unaltered, is inadequate. The most usual alternative
|
argument unaltered, is inadequate. The most usual alternative
|
definition of this macro prepends an underscore to the label
|
definition of this macro prepends an underscore to the label
|
name.
|
name.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Base types
|
Base types
|
|
|
cyg_halint8
|
cyg_halint8
|
cyg_halint16
|
cyg_halint16
|
cyg_halint32
|
cyg_halint32
|
cyg_halint64
|
cyg_halint64
|
cyg_halcount8
|
cyg_halcount8
|
cyg_halcount16
|
cyg_halcount16
|
cyg_halcount32
|
cyg_halcount32
|
cyg_halcount64
|
cyg_halcount64
|
cyg_halbool
|
cyg_halbool
|
|
|
|
|
These macros define the C base types that should be used to define
|
These macros define the C base types that should be used to define
|
variables of the given size. They only need to be defined if the
|
variables of the given size. They only need to be defined if the
|
default types specified in cyg/infra/cyg_type.h
|
default types specified in cyg/infra/cyg_type.h
|
cannot be used. Note that these are only the base types, they will be
|
cannot be used. Note that these are only the base types, they will be
|
composed with signed and
|
composed with signed and
|
unsigned to form full type specifications.
|
unsigned to form full type specifications.
|
|
|
|
|
|
|
|
|
|
|
|
|
Atomic types
|
Atomic types
|
|
|
cyg_halatomic CYG_ATOMIC
|
cyg_halatomic CYG_ATOMIC
|
|
|
|
|
These types are guaranteed to be read or written in a single
|
These types are guaranteed to be read or written in a single
|
uninterruptible operation. It is architecture defined what size this
|
uninterruptible operation. It is architecture defined what size this
|
type is, but it will be at least a byte.
|
type is, but it will be at least a byte.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Architecture Characterization
|
Architecture Characterization
|
|
|
|
|
These are definition that are related to the basic architecture of the
|
These are definition that are related to the basic architecture of the
|
CPU. These include the CPU context save format, context switching, bit
|
CPU. These include the CPU context save format, context switching, bit
|
twiddling, breakpoints, stack sizes and address translation.
|
twiddling, breakpoints, stack sizes and address translation.
|
|
|
|
|
|
|
Most of these definition are found in
|
Most of these definition are found in
|
cyg/hal/hal_arch.h. This file is supplied by the
|
cyg/hal/hal_arch.h. This file is supplied by the
|
architecture HAL. If there are variant or platform specific
|
architecture HAL. If there are variant or platform specific
|
definitions then these will be found in
|
definitions then these will be found in
|
cyg/hal/var_arch.h or
|
cyg/hal/var_arch.h or
|
cyg/hal/plf_arch.h. These files are include
|
cyg/hal/plf_arch.h. These files are include
|
automatically by this header, so need not be included explicitly.
|
automatically by this header, so need not be included explicitly.
|
|
|
|
|
|
|
|
|
|
|
Register Save Format
|
Register Save Format
|
|
|
typedef struct HAL_SavedRegisters
|
typedef struct HAL_SavedRegisters
|
{
|
{
|
/* architecture-dependent list of registers to be saved */
|
/* architecture-dependent list of registers to be saved */
|
} HAL_SavedRegisters;
|
} HAL_SavedRegisters;
|
|
|
|
|
This structure describes the layout of a saved machine state on the
|
This structure describes the layout of a saved machine state on the
|
stack. Such states are saved during thread context switches,
|
stack. Such states are saved during thread context switches,
|
interrupts and exceptions. Different quantities of state may be saved
|
interrupts and exceptions. Different quantities of state may be saved
|
during each of these, but usually a thread context state is a subset
|
during each of these, but usually a thread context state is a subset
|
of the interrupt state which is itself a subset of an exception state.
|
of the interrupt state which is itself a subset of an exception state.
|
For debugging purposes, the same structure is used for all three
|
For debugging purposes, the same structure is used for all three
|
purposes, but where these states are significantly different, this
|
purposes, but where these states are significantly different, this
|
structure may contain a union of the three states.
|
structure may contain a union of the three states.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Thread Context Initialization
|
Thread Context Initialization
|
|
|
|
|
HAL_THREAD_INIT_CONTEXT( sp, arg, entry, id )
|
HAL_THREAD_INIT_CONTEXT( sp, arg, entry, id )
|
|
|
|
|
|
|
This macro initializes a thread's context so that
|
This macro initializes a thread's context so that
|
it may be switched to by HAL_THREAD_SWITCH_CONTEXT().
|
it may be switched to by HAL_THREAD_SWITCH_CONTEXT().
|
The arguments are:
|
The arguments are:
|
|
|
|
|
|
|
sp
|
sp
|
|
|
|
|
A location containing the current value of the thread's stack
|
A location containing the current value of the thread's stack
|
pointer. This should be a variable or a structure field. The SP
|
pointer. This should be a variable or a structure field. The SP
|
value will be read out of here and an adjusted value written
|
value will be read out of here and an adjusted value written
|
back.
|
back.
|
|
|
|
|
|
|
|
|
|
|
arg
|
arg
|
|
|
|
|
A value that is passed as the first argument to the entry
|
A value that is passed as the first argument to the entry
|
point function.
|
point function.
|
|
|
|
|
|
|
|
|
entry
|
entry
|
|
|
|
|
The address of an entry point function. This will be called
|
The address of an entry point function. This will be called
|
according the C calling conventions, and the value of
|
according the C calling conventions, and the value of
|
arg will be passed as the first
|
arg will be passed as the first
|
argument. This function should have the following type signature
|
argument. This function should have the following type signature
|
void entry(CYG_ADDRWORD arg).
|
void entry(CYG_ADDRWORD arg).
|
|
|
|
|
|
|
|
|
id
|
id
|
|
|
|
|
A thread id value. This is only used for debugging purposes,
|
A thread id value. This is only used for debugging purposes,
|
it is ORed into the initialization pattern for unused registers
|
it is ORed into the initialization pattern for unused registers
|
and may be used to help identify the thread from its register dump.
|
and may be used to help identify the thread from its register dump.
|
The least significant 16 bits of this value should be zero to allow
|
The least significant 16 bits of this value should be zero to allow
|
space for a register identifier.
|
space for a register identifier.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Thread Context Switching
|
Thread Context Switching
|
|
|
|
|
HAL_THREAD_LOAD_CONTEXT( to )
|
HAL_THREAD_LOAD_CONTEXT( to )
|
HAL_THREAD_SWITCH_CONTEXT( from, to )
|
HAL_THREAD_SWITCH_CONTEXT( from, to )
|
|
|
|
|
These macros implement the thread switch code. The arguments are:
|
These macros implement the thread switch code. The arguments are:
|
|
|
|
|
|
|
|
|
from
|
from
|
|
|
|
|
A pointer to a location where the stack pointer of the current
|
A pointer to a location where the stack pointer of the current
|
thread will be stored.
|
thread will be stored.
|
|
|
|
|
|
|
|
|
to
|
to
|
|
|
|
|
A pointer to a location from where the stack pointer of the next
|
A pointer to a location from where the stack pointer of the next
|
thread will be read.
|
thread will be read.
|
|
|
|
|
|
|
|
|
|
|
|
|
For HAL_THREAD_LOAD_CONTEXT() the current CPU
|
For HAL_THREAD_LOAD_CONTEXT() the current CPU
|
state is discarded and the state of the destination thread is
|
state is discarded and the state of the destination thread is
|
loaded. This is only used once, to load the first thread when the
|
loaded. This is only used once, to load the first thread when the
|
scheduler is started.
|
scheduler is started.
|
|
|
|
|
|
|
For HAL_THREAD_SWITCH_CONTEXT() the state of the
|
For HAL_THREAD_SWITCH_CONTEXT() the state of the
|
current thread is saved onto its stack, using the current value of the
|
current thread is saved onto its stack, using the current value of the
|
stack pointer, and the address of the saved state placed in
|
stack pointer, and the address of the saved state placed in
|
*from. The value in
|
*from. The value in
|
*to is then read and the state of the new
|
*to is then read and the state of the new
|
thread is loaded from it.
|
thread is loaded from it.
|
|
|
|
|
|
|
While these two operations may be implemented with inline assembler,
|
While these two operations may be implemented with inline assembler,
|
they are normally implemented as calls to assembly code functions in
|
they are normally implemented as calls to assembly code functions in
|
the HAL. There are two advantages to doing it this way. First, the
|
the HAL. There are two advantages to doing it this way. First, the
|
return link of the call provides a convenient PC value to be used in
|
return link of the call provides a convenient PC value to be used in
|
the saved context. Second, the calling conventions mean that the
|
the saved context. Second, the calling conventions mean that the
|
compiler will have already saved the caller-saved registers before the
|
compiler will have already saved the caller-saved registers before the
|
call, so the HAL need only save the callee-saved registers.
|
call, so the HAL need only save the callee-saved registers.
|
|
|
|
|
|
|
The implementation of HAL_THREAD_SWITCH_CONTEXT()
|
The implementation of HAL_THREAD_SWITCH_CONTEXT()
|
saves the current CPU state on the stack, including the current
|
saves the current CPU state on the stack, including the current
|
interrupt state (or at least the register that contains it). For
|
interrupt state (or at least the register that contains it). For
|
debugging purposes it is useful to save the entire register set, but
|
debugging purposes it is useful to save the entire register set, but
|
for performance only the ABI-defined callee-saved registers need be
|
for performance only the ABI-defined callee-saved registers need be
|
saved. If it is implemented, the option
|
saved. If it is implemented, the option
|
CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM controls
|
CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM controls
|
how many registers are saved.
|
how many registers are saved.
|
|
|
|
|
|
|
The implementation of HAL_THREAD_LOAD_CONTEXT()
|
The implementation of HAL_THREAD_LOAD_CONTEXT()
|
loads a thread context, destroying the current context. With a little
|
loads a thread context, destroying the current context. With a little
|
care this can be implemented by sharing code with
|
care this can be implemented by sharing code with
|
HAL_THREAD_SWITCH_CONTEXT(). To load a thread
|
HAL_THREAD_SWITCH_CONTEXT(). To load a thread
|
context simply requires the saved registers to be restored from the
|
context simply requires the saved registers to be restored from the
|
stack and a jump or return made back to the saved PC.
|
stack and a jump or return made back to the saved PC.
|
|
|
|
|
|
|
Note that interrupts are not disabled during this process, any
|
Note that interrupts are not disabled during this process, any
|
interrupts that occur will be delivered onto the stack to which the
|
interrupts that occur will be delivered onto the stack to which the
|
current CPU stack pointer points. Hence the stack pointer
|
current CPU stack pointer points. Hence the stack pointer
|
should never be invalid, or loaded with a value that might cause the
|
should never be invalid, or loaded with a value that might cause the
|
saved state to become corrupted by an interrupt. However, the current
|
saved state to become corrupted by an interrupt. However, the current
|
interrupt state is saved and restored as part of the thread
|
interrupt state is saved and restored as part of the thread
|
context. If a thread disables interrupts and does something to cause a
|
context. If a thread disables interrupts and does something to cause a
|
context switch, interrupts may be re-enabled on switching to another
|
context switch, interrupts may be re-enabled on switching to another
|
thread. Interrupts will be disabled again when the original thread
|
thread. Interrupts will be disabled again when the original thread
|
regains control.
|
regains control.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bit indexing
|
Bit indexing
|
|
|
|
|
HAL_LSBIT_INDEX( index, mask )
|
HAL_LSBIT_INDEX( index, mask )
|
HAL_MSBIT_INDEX( index, mask )
|
HAL_MSBIT_INDEX( index, mask )
|
|
|
|
|
|
|
These macros place in index the bit index of
|
These macros place in index the bit index of
|
the least significant bit in mask. Some
|
the least significant bit in mask. Some
|
architectures have instruction level support for one or other of these
|
architectures have instruction level support for one or other of these
|
operations. If no architectural support is available, then these
|
operations. If no architectural support is available, then these
|
macros may call C functions to do the job.
|
macros may call C functions to do the job.
|
|
|
|
|
|
|
|
|
|
|
|
|
Idle thread activity
|
Idle thread activity
|
|
|
|
|
HAL_IDLE_THREAD_ACTION( count )
|
HAL_IDLE_THREAD_ACTION( count )
|
|
|
|
|
|
|
It may be necessary under some circumstances for the HAL to execute
|
It may be necessary under some circumstances for the HAL to execute
|
code in the kernel idle thread's loop. An example might be to execute
|
code in the kernel idle thread's loop. An example might be to execute
|
a processor halt instruction. This macro provides a portable way of
|
a processor halt instruction. This macro provides a portable way of
|
doing this. The argument is a copy of the idle thread's loop counter,
|
doing this. The argument is a copy of the idle thread's loop counter,
|
and may be used to trigger actions at longer intervals than every
|
and may be used to trigger actions at longer intervals than every
|
loop.
|
loop.
|
|
|
|
|
|
|
|
|
|
|
|
|
Reorder barrier
|
Reorder barrier
|
|
|
|
|
HAL_REORDER_BARRIER()
|
HAL_REORDER_BARRIER()
|
|
|
|
|
|
|
When optimizing the compiler can reorder code. In some parts of
|
When optimizing the compiler can reorder code. In some parts of
|
multi-threaded systems, where the order of actions is vital, this can
|
multi-threaded systems, where the order of actions is vital, this can
|
sometimes cause problems. This macro may be inserted into places where
|
sometimes cause problems. This macro may be inserted into places where
|
reordering should not happen and prevents code being migrated across
|
reordering should not happen and prevents code being migrated across
|
it by the compiler optimizer. It should be placed between statements
|
it by the compiler optimizer. It should be placed between statements
|
that must be executed in the order written in the code.
|
that must be executed in the order written in the code.
|
|
|
|
|
|
|
|
|
|
|
|
|
Breakpoint support
|
Breakpoint support
|
|
|
|
|
HAL_BREAKPOINT( label )
|
HAL_BREAKPOINT( label )
|
HAL_BREAKINST
|
HAL_BREAKINST
|
HAL_BREAKINST_SIZE
|
HAL_BREAKINST_SIZE
|
|
|
|
|
|
|
These macros provide support for breakpoints.
|
These macros provide support for breakpoints.
|
|
|
|
|
|
|
HAL_BREAKPOINT() executes a breakpoint
|
HAL_BREAKPOINT() executes a breakpoint
|
instruction. The label is defined at the breakpoint instruction so
|
instruction. The label is defined at the breakpoint instruction so
|
that exception code can detect which breakpoint was executed.
|
that exception code can detect which breakpoint was executed.
|
|
|
|
|
|
|
HAL_BREAKINST contains the breakpoint instruction
|
HAL_BREAKINST contains the breakpoint instruction
|
code as an integer value. HAL_BREAKINST_SIZE is
|
code as an integer value. HAL_BREAKINST_SIZE is
|
the size of that breakpoint instruction in bytes. Together these
|
the size of that breakpoint instruction in bytes. Together these
|
may be used to place a breakpoint in any code.
|
may be used to place a breakpoint in any code.
|
|
|
|
|
|
|
|
|
|
|
|
|
GDB support
|
GDB support
|
|
|
|
|
HAL_THREAD_GET_SAVED_REGISTERS( sp, regs )
|
HAL_THREAD_GET_SAVED_REGISTERS( sp, regs )
|
HAL_GET_GDB_REGISTERS( regval, regs )
|
HAL_GET_GDB_REGISTERS( regval, regs )
|
HAL_SET_GDB_REGISTERS( regs, regval )
|
HAL_SET_GDB_REGISTERS( regs, regval )
|
|
|
|
|
|
|
These macros provide support for interfacing GDB to the HAL.
|
These macros provide support for interfacing GDB to the HAL.
|
|
|
|
|
|
|
HAL_THREAD_GET_SAVED_REGISTERS() extracts a
|
HAL_THREAD_GET_SAVED_REGISTERS() extracts a
|
pointer to a HAL_SavedRegisters structure
|
pointer to a HAL_SavedRegisters structure
|
from a stack pointer value. The stack pointer passed in should be the
|
from a stack pointer value. The stack pointer passed in should be the
|
value saved by the thread context macros. The macro will assign a
|
value saved by the thread context macros. The macro will assign a
|
pointer to the HAL_SavedRegisters structure
|
pointer to the HAL_SavedRegisters structure
|
to the variable passed as the second argument.
|
to the variable passed as the second argument.
|
|
|
|
|
|
|
HAL_GET_GDB_REGISTERS() translates a register
|
HAL_GET_GDB_REGISTERS() translates a register
|
state as saved by the HAL and into a register dump in the format
|
state as saved by the HAL and into a register dump in the format
|
expected by GDB. It takes a pointer to a
|
expected by GDB. It takes a pointer to a
|
HAL_SavedRegisters structure in the
|
HAL_SavedRegisters structure in the
|
regs argument and a pointer to the memory to
|
regs argument and a pointer to the memory to
|
contain the GDB register dump in the regval
|
contain the GDB register dump in the regval
|
argument.
|
argument.
|
|
|
|
|
|
|
HAL_SET_GDB_REGISTERS() translates a GDB format
|
HAL_SET_GDB_REGISTERS() translates a GDB format
|
register dump into a the format expected by the HAL. It takes a
|
register dump into a the format expected by the HAL. It takes a
|
pointer to the memory containing the GDB register dump in the
|
pointer to the memory containing the GDB register dump in the
|
regval argument and a pointer to a
|
regval argument and a pointer to a
|
HAL_SavedRegisters structure
|
HAL_SavedRegisters structure
|
in the regs argument.
|
in the regs argument.
|
|
|
|
|
|
|
|
|
|
|
|
|
Setjmp and longjmp support
|
Setjmp and longjmp support
|
|
|
|
|
CYGARC_JMP_BUF_SIZE
|
CYGARC_JMP_BUF_SIZE
|
hal_jmp_buf[CYGARC_JMP_BUF_SIZE]
|
hal_jmp_buf[CYGARC_JMP_BUF_SIZE]
|
hal_setjmp( hal_jmp_buf env )
|
hal_setjmp( hal_jmp_buf env )
|
hal_longjmp( hal_jmp_buf env, int val )
|
hal_longjmp( hal_jmp_buf env, int val )
|
|
|
|
|
|
|
These functions provide support for the C
|
These functions provide support for the C
|
setjmp() and longjmp()
|
setjmp() and longjmp()
|
functions. Refer to the C library for further information.
|
functions. Refer to the C library for further information.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stack Sizes
|
Stack Sizes
|
|
|
CYGNUM_HAL_STACK_SIZE_MINIMUM
|
CYGNUM_HAL_STACK_SIZE_MINIMUM
|
CYGNUM_HAL_STACK_SIZE_TYPICAL
|
CYGNUM_HAL_STACK_SIZE_TYPICAL
|
|
|
|
|
|
|
The values of these macros define the minimum and typical sizes of
|
The values of these macros define the minimum and typical sizes of
|
thread stacks.
|
thread stacks.
|
|
|
|
|
|
|
CYGNUM_HAL_STACK_SIZE_MINIMUM defines the minimum
|
CYGNUM_HAL_STACK_SIZE_MINIMUM defines the minimum
|
size of a thread stack. This is enough for the thread to function
|
size of a thread stack. This is enough for the thread to function
|
correctly within eCos and allows it to take interrupts and context
|
correctly within eCos and allows it to take interrupts and context
|
switches. There should also be enough space for a simple thread entry
|
switches. There should also be enough space for a simple thread entry
|
function to execute and call basic kernel operations on objects like
|
function to execute and call basic kernel operations on objects like
|
mutexes and semaphores. However there will not be enough room for much
|
mutexes and semaphores. However there will not be enough room for much
|
more than this. When creating stacks for their own threads,
|
more than this. When creating stacks for their own threads,
|
applications should determine the stack usage needed for application
|
applications should determine the stack usage needed for application
|
purposes and then add
|
purposes and then add
|
CYGNUM_HAL_STACK_SIZE_MINIMUM.
|
CYGNUM_HAL_STACK_SIZE_MINIMUM.
|
|
|
|
|
|
|
CYGNUM_HAL_STACK_SIZE_TYPICAL is a reasonable increment over
|
CYGNUM_HAL_STACK_SIZE_TYPICAL is a reasonable increment over
|
CYGNUM_HAL_STACK_SIZE_MINIMUM, usually about 1kB. This should be
|
CYGNUM_HAL_STACK_SIZE_MINIMUM, usually about 1kB. This should be
|
adequate for most modest thread needs. Only threads that need to
|
adequate for most modest thread needs. Only threads that need to
|
define significant amounts of local data, or have very deep call trees
|
define significant amounts of local data, or have very deep call trees
|
should need to use a larger stack size.
|
should need to use a larger stack size.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Address Translation
|
Address Translation
|
|
|
|
|
CYGARC_CACHED_ADDRESS(addr)
|
CYGARC_CACHED_ADDRESS(addr)
|
CYGARC_UNCACHED_ADDRESS(addr)
|
CYGARC_UNCACHED_ADDRESS(addr)
|
CYGARC_PHYSICAL_ADDRESS(addr)
|
CYGARC_PHYSICAL_ADDRESS(addr)
|
|
|
|
|
|
|
These macros provide address translation between different views of
|
These macros provide address translation between different views of
|
memory. In many architectures a given memory location may be visible
|
memory. In many architectures a given memory location may be visible
|
at different addresses in both cached and uncached forms. It is also
|
at different addresses in both cached and uncached forms. It is also
|
possible that the MMU or some other address translation unit in the
|
possible that the MMU or some other address translation unit in the
|
CPU presents memory to the program at a different virtual address to
|
CPU presents memory to the program at a different virtual address to
|
its physical address on the bus.
|
its physical address on the bus.
|
|
|
|
|
|
|
CYGARC_CACHED_ADDRESS() translates the given
|
CYGARC_CACHED_ADDRESS() translates the given
|
address to its location in cached memory. This is typically where the
|
address to its location in cached memory. This is typically where the
|
application will access the memory.
|
application will access the memory.
|
|
|
|
|
|
|
CYGARC_UNCACHED_ADDRESS() translates the given
|
CYGARC_UNCACHED_ADDRESS() translates the given
|
address to its location in uncached memory. This is typically where
|
address to its location in uncached memory. This is typically where
|
device drivers will access the memory to avoid cache problems. It may
|
device drivers will access the memory to avoid cache problems. It may
|
additionally be necessary for the cache to be flushed before the
|
additionally be necessary for the cache to be flushed before the
|
contents of this location is fully valid.
|
contents of this location is fully valid.
|
|
|
|
|
|
|
CYGARC_PHYSICAL_ADDRESS() translates the given
|
CYGARC_PHYSICAL_ADDRESS() translates the given
|
address to its location in the physical address space. This is
|
address to its location in the physical address space. This is
|
typically the address that needs to be passed to device hardware such
|
typically the address that needs to be passed to device hardware such
|
as a DMA engine, ethernet device or PCI bus bridge. The physical
|
as a DMA engine, ethernet device or PCI bus bridge. The physical
|
address may not be directly accessible to the program, it may be
|
address may not be directly accessible to the program, it may be
|
re-mapped by address translation.
|
re-mapped by address translation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Global Pointer
|
Global Pointer
|
|
|
|
|
CYGARC_HAL_SAVE_GP()
|
CYGARC_HAL_SAVE_GP()
|
CYGARC_HAL_RESTORE_GP()
|
CYGARC_HAL_RESTORE_GP()
|
|
|
|
|
|
|
These macros insert code to save and restore any global data pointer
|
These macros insert code to save and restore any global data pointer
|
that the ABI uses. These are necessary when switching context between
|
that the ABI uses. These are necessary when switching context between
|
two eCos instances - for example between an eCos application and
|
two eCos instances - for example between an eCos application and
|
RedBoot.
|
RedBoot.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interrupt Handling
|
Interrupt Handling
|
|
|
|
|
These interfaces contain definitions related to interrupt
|
These interfaces contain definitions related to interrupt
|
handling. They include definitions of exception and interrupt numbers,
|
handling. They include definitions of exception and interrupt numbers,
|
interrupt enabling and masking, and realtime clock operations.
|
interrupt enabling and masking, and realtime clock operations.
|
|
|
|
|
|
|
These definitions are normally found in
|
These definitions are normally found in
|
cyg/hal/hal_intr.h. This file is supplied by the
|
cyg/hal/hal_intr.h. This file is supplied by the
|
architecture HAL. Any variant or platform specific definitions will
|
architecture HAL. Any variant or platform specific definitions will
|
be found in cyg/hal/var_intr.h,
|
be found in cyg/hal/var_intr.h,
|
cyg/hal/plf_intr.h or
|
cyg/hal/plf_intr.h or
|
cyg/hal/hal_platform_ints.h in the variant or platform
|
cyg/hal/hal_platform_ints.h in the variant or platform
|
HAL, depending on the exact target. These files are include
|
HAL, depending on the exact target. These files are include
|
automatically by this header, so need not be included explicitly.
|
automatically by this header, so need not be included explicitly.
|
|
|
|
|
|
|
|
|
|
|
Vector numbers
|
Vector numbers
|
|
|
|
|
CYGNUM_HAL_VECTOR_XXXX
|
CYGNUM_HAL_VECTOR_XXXX
|
CYGNUM_HAL_VSR_MIN
|
CYGNUM_HAL_VSR_MIN
|
CYGNUM_HAL_VSR_MAX
|
CYGNUM_HAL_VSR_MAX
|
CYGNUM_HAL_VSR_COUNT
|
CYGNUM_HAL_VSR_COUNT
|
|
|
CYGNUM_HAL_INTERRUPT_XXXX
|
CYGNUM_HAL_INTERRUPT_XXXX
|
CYGNUM_HAL_ISR_MIN
|
CYGNUM_HAL_ISR_MIN
|
CYGNUM_HAL_ISR_MAX
|
CYGNUM_HAL_ISR_MAX
|
CYGNUM_HAL_ISR_COUNT
|
CYGNUM_HAL_ISR_COUNT
|
|
|
CYGNUM_HAL_EXCEPTION_XXXX
|
CYGNUM_HAL_EXCEPTION_XXXX
|
CYGNUM_HAL_EXCEPTION_MIN
|
CYGNUM_HAL_EXCEPTION_MIN
|
CYGNUM_HAL_EXCEPTION_MAX
|
CYGNUM_HAL_EXCEPTION_MAX
|
CYGNUM_HAL_EXCEPTION_COUNT
|
CYGNUM_HAL_EXCEPTION_COUNT
|
|
|
|
|
|
|
All possible VSR, interrupt and exception vectors are specified here,
|
All possible VSR, interrupt and exception vectors are specified here,
|
together with maximum and minimum values for range checking. While the
|
together with maximum and minimum values for range checking. While the
|
VSR and exception numbers will be defined in this file, the interrupt
|
VSR and exception numbers will be defined in this file, the interrupt
|
numbers will normally be defined in the variant or platform HAL file
|
numbers will normally be defined in the variant or platform HAL file
|
that is included by this header.
|
that is included by this header.
|
|
|
|
|
|
|
There are two ranges of numbers, those for the vector service
|
There are two ranges of numbers, those for the vector service
|
routines and those for the interrupt service routines. The relationship
|
routines and those for the interrupt service routines. The relationship
|
between these two ranges is undefined, and no equivalence should
|
between these two ranges is undefined, and no equivalence should
|
be assumed if vectors from the two ranges coincide.
|
be assumed if vectors from the two ranges coincide.
|
|
|
|
|
|
|
The VSR vectors correspond to the set of exception vectors that can be
|
The VSR vectors correspond to the set of exception vectors that can be
|
delivered by the CPU architecture, many of these will be internal
|
delivered by the CPU architecture, many of these will be internal
|
exception traps. The ISR vectors correspond to the set of external
|
exception traps. The ISR vectors correspond to the set of external
|
interrupts that can be delivered and are usually determined by extra
|
interrupts that can be delivered and are usually determined by extra
|
decoding of the interrupt controller by the interrupt VSR.
|
decoding of the interrupt controller by the interrupt VSR.
|
|
|
|
|
|
|
Where a CPU supports synchronous exceptions, the range of such
|
Where a CPU supports synchronous exceptions, the range of such
|
exceptions allowed are defined by CYGNUM_HAL_EXCEPTION_MIN and
|
exceptions allowed are defined by CYGNUM_HAL_EXCEPTION_MIN and
|
CYGNUM_HAL_EXCEPTION_MAX. The
|
CYGNUM_HAL_EXCEPTION_MAX. The
|
CYGNUM_HAL_EXCEPTION_XXXX definitions are
|
CYGNUM_HAL_EXCEPTION_XXXX definitions are
|
standard names used by target independent code to test for the
|
standard names used by target independent code to test for the
|
presence of particular exceptions in the architecture. The actual
|
presence of particular exceptions in the architecture. The actual
|
exception numbers will normally correspond to the VSR exception
|
exception numbers will normally correspond to the VSR exception
|
range. In future other exceptions generated by the system software
|
range. In future other exceptions generated by the system software
|
(such as stack overflow) may be added.
|
(such as stack overflow) may be added.
|
|
|
|
|
|
|
CYGNUM_HAL_ISR_COUNT, CYGNUM_HAL_VSR_COUNT and
|
CYGNUM_HAL_ISR_COUNT, CYGNUM_HAL_VSR_COUNT and
|
CYGNUM_HAL_EXCEPTION_COUNT define the number of
|
CYGNUM_HAL_EXCEPTION_COUNT define the number of
|
ISRs, VSRs and EXCEPTIONs respectively for the purposes of defining
|
ISRs, VSRs and EXCEPTIONs respectively for the purposes of defining
|
arrays etc. There might be a translation from the supplied vector
|
arrays etc. There might be a translation from the supplied vector
|
numbers into array offsets. Hence
|
numbers into array offsets. Hence
|
CYGNUM_HAL_XXX_COUNT may not simply be
|
CYGNUM_HAL_XXX_COUNT may not simply be
|
CYGNUM_HAL_XXX_MAX - CYGNUM_HAL_XXX_MIN or CYGNUM_HAL_XXX_MAX+1.
|
CYGNUM_HAL_XXX_MAX - CYGNUM_HAL_XXX_MIN or CYGNUM_HAL_XXX_MAX+1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interrupt state control
|
Interrupt state control
|
|
|
|
|
CYG_INTERRUPT_STATE
|
CYG_INTERRUPT_STATE
|
HAL_DISABLE_INTERRUPTS( old )
|
HAL_DISABLE_INTERRUPTS( old )
|
HAL_RESTORE_INTERRUPTS( old )
|
HAL_RESTORE_INTERRUPTS( old )
|
HAL_ENABLE_INTERRUPTS()
|
HAL_ENABLE_INTERRUPTS()
|
HAL_QUERY_INTERRUPTS( state )
|
HAL_QUERY_INTERRUPTS( state )
|
|
|
|
|
|
|
These macros provide control over the state of the CPUs interrupt mask
|
These macros provide control over the state of the CPUs interrupt mask
|
mechanism. They should normally manipulate a CPU status register to
|
mechanism. They should normally manipulate a CPU status register to
|
enable and disable interrupt delivery. They should not access an
|
enable and disable interrupt delivery. They should not access an
|
interrupt controller.
|
interrupt controller.
|
|
|
|
|
|
|
|
|
CYG_INTERRUPT_STATE is a data type that should be
|
CYG_INTERRUPT_STATE is a data type that should be
|
used to store the interrupt state returned by
|
used to store the interrupt state returned by
|
HAL_DISABLE_INTERRUPTS() and
|
HAL_DISABLE_INTERRUPTS() and
|
HAL_QUERY_INTERRUPTS() and passed to
|
HAL_QUERY_INTERRUPTS() and passed to
|
HAL_RESTORE_INTERRUPTS().
|
HAL_RESTORE_INTERRUPTS().
|
|
|
|
|
|
|
HAL_DISABLE_INTERRUPTS() disables the delivery of
|
HAL_DISABLE_INTERRUPTS() disables the delivery of
|
interrupts and stores the original state of the interrupt mask in the
|
interrupts and stores the original state of the interrupt mask in the
|
variable passed in the old argument.
|
variable passed in the old argument.
|
|
|
|
|
|
|
HAL_RESTORE_INTERRUPTS() restores the state of
|
HAL_RESTORE_INTERRUPTS() restores the state of
|
the interrupt mask to that recorded in old.
|
the interrupt mask to that recorded in old.
|
|
|
|
|
|
|
HAL_ENABLE_INTERRUPTS() simply enables interrupts
|
HAL_ENABLE_INTERRUPTS() simply enables interrupts
|
regardless of the current state of the mask.
|
regardless of the current state of the mask.
|
|
|
|
|
|
|
HAL_QUERY_INTERRUPTS() stores the state of the
|
HAL_QUERY_INTERRUPTS() stores the state of the
|
interrupt mask in the variable passed in the
|
interrupt mask in the variable passed in the
|
state argument. The state stored here should also be
|
state argument. The state stored here should also be
|
capable of being passed to
|
capable of being passed to
|
HAL_RESTORE_INTERRUPTS() at a later point.
|
HAL_RESTORE_INTERRUPTS() at a later point.
|
|
|
|
|
|
|
It is at the HAL implementer’s discretion exactly
|
It is at the HAL implementer’s discretion exactly
|
which interrupts are masked by this mechanism. Where a CPU has more
|
which interrupts are masked by this mechanism. Where a CPU has more
|
than one interrupt type that may be masked separately (e.g. the
|
than one interrupt type that may be masked separately (e.g. the
|
ARM's IRQ and FIQ) only those that can raise DSRs need
|
ARM's IRQ and FIQ) only those that can raise DSRs need
|
to be masked here. A separate architecture specific mechanism may
|
to be masked here. A separate architecture specific mechanism may
|
then be used to control the other interrupt types.
|
then be used to control the other interrupt types.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ISR and VSR management
|
ISR and VSR management
|
|
|
|
|
HAL_INTERRUPT_IN_USE( vector, state )
|
HAL_INTERRUPT_IN_USE( vector, state )
|
HAL_INTERRUPT_ATTACH( vector, isr, data, object )
|
HAL_INTERRUPT_ATTACH( vector, isr, data, object )
|
HAL_INTERRUPT_DETACH( vector, isr )
|
HAL_INTERRUPT_DETACH( vector, isr )
|
HAL_VSR_SET( vector, vsr, poldvsr )
|
HAL_VSR_SET( vector, vsr, poldvsr )
|
HAL_VSR_GET( vector, pvsr )
|
HAL_VSR_GET( vector, pvsr )
|
HAL_VSR_SET_TO_ECOS_HANDLER( vector, poldvsr )
|
HAL_VSR_SET_TO_ECOS_HANDLER( vector, poldvsr )
|
|
|
|
|
|
|
These macros manage the attachment of interrupt and vector service
|
These macros manage the attachment of interrupt and vector service
|
routines to interrupt and exception vectors respectively.
|
routines to interrupt and exception vectors respectively.
|
|
|
|
|
|
|
HAL_INTERRUPT_IN_USE() tests the state of the
|
HAL_INTERRUPT_IN_USE() tests the state of the
|
supplied interrupt vector and sets the value of the state parameter to
|
supplied interrupt vector and sets the value of the state parameter to
|
either 1 or 0 depending on whether there is already an ISR attached to
|
either 1 or 0 depending on whether there is already an ISR attached to
|
the vector. The HAL will only allow one ISR to be attached to each
|
the vector. The HAL will only allow one ISR to be attached to each
|
vector, so it is a good idea to use this function before using
|
vector, so it is a good idea to use this function before using
|
HAL_INTERRUPT_ATTACH().
|
HAL_INTERRUPT_ATTACH().
|
|
|
|
|
|
|
HAL_INTERRUPT_ATTACH() attaches
|
HAL_INTERRUPT_ATTACH() attaches
|
the ISR, data pointer and object pointer to the given
|
the ISR, data pointer and object pointer to the given
|
vector. When an interrupt occurs on this
|
vector. When an interrupt occurs on this
|
vector the ISR is called using the C calling convention and the vector
|
vector the ISR is called using the C calling convention and the vector
|
number and data pointer are passed to it as the first and second
|
number and data pointer are passed to it as the first and second
|
arguments respectively.
|
arguments respectively.
|
|
|
|
|
|
|
HAL_INTERRUPT_DETACH() detaches the ISR from the
|
HAL_INTERRUPT_DETACH() detaches the ISR from the
|
vector.
|
vector.
|
|
|
|
|
|
|
HAL_VSR_SET() replaces the VSR attached to the
|
HAL_VSR_SET() replaces the VSR attached to the
|
vector with the replacement supplied in
|
vector with the replacement supplied in
|
vsr. The old VSR is returned in the location
|
vsr. The old VSR is returned in the location
|
pointed to by pvsr.
|
pointed to by pvsr.
|
|
|
|
|
|
|
HAL_VSR_GET() assigns
|
HAL_VSR_GET() assigns
|
a copy of the VSR to the location pointed to by pvsr.
|
a copy of the VSR to the location pointed to by pvsr.
|
|
|
|
|
|
|
HAL_VSR_SET_TO_ECOS_HANDLER() ensures that the
|
HAL_VSR_SET_TO_ECOS_HANDLER() ensures that the
|
VSR for a specific exception is pointing at the eCos exception VSR and
|
VSR for a specific exception is pointing at the eCos exception VSR and
|
not one for RedBoot or some other ROM monitor. The default when
|
not one for RedBoot or some other ROM monitor. The default when
|
running under RedBoot is for exceptions to be handled by RedBoot and
|
running under RedBoot is for exceptions to be handled by RedBoot and
|
passed to GDB. This macro diverts the exception to eCos so that it may
|
passed to GDB. This macro diverts the exception to eCos so that it may
|
be handled by application code. The arguments are the VSR vector to be
|
be handled by application code. The arguments are the VSR vector to be
|
replaces, and a location in which to store the old VSR pointer, so
|
replaces, and a location in which to store the old VSR pointer, so
|
that it may be replaced at a later point.
|
that it may be replaced at a later point.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interrupt controller management
|
Interrupt controller management
|
|
|
|
|
HAL_INTERRUPT_MASK( vector )
|
HAL_INTERRUPT_MASK( vector )
|
HAL_INTERRUPT_UNMASK( vector )
|
HAL_INTERRUPT_UNMASK( vector )
|
HAL_INTERRUPT_ACKNOWLEDGE( vector )
|
HAL_INTERRUPT_ACKNOWLEDGE( vector )
|
HAL_INTERRUPT_CONFIGURE( vector, level, up )
|
HAL_INTERRUPT_CONFIGURE( vector, level, up )
|
HAL_INTERRUPT_SET_LEVEL( vector, level )
|
HAL_INTERRUPT_SET_LEVEL( vector, level )
|
|
|
|
|
|
|
These macros exert control over any prioritized interrupt
|
These macros exert control over any prioritized interrupt
|
controller that is present. If no priority controller exists, then
|
controller that is present. If no priority controller exists, then
|
these macros should be empty.
|
these macros should be empty.
|
|
|
|
|
|
|
|
|
These macros may not be reentrant, so care should be taken to
|
These macros may not be reentrant, so care should be taken to
|
prevent them being called while interrupts are enabled. This means
|
prevent them being called while interrupts are enabled. This means
|
that they can be safely used in initialization code before
|
that they can be safely used in initialization code before
|
interrupts are enabled, and in ISRs. In DSRs, ASRs and thread code,
|
interrupts are enabled, and in ISRs. In DSRs, ASRs and thread code,
|
however, interrupts must be disabled before these macros are
|
however, interrupts must be disabled before these macros are
|
called. Here is an example for use in a DSR where the interrupt
|
called. Here is an example for use in a DSR where the interrupt
|
source is unmasked after data processing:
|
source is unmasked after data processing:
|
|
|
|
|
...
|
...
|
HAL_DISABLE_INTERRUPTS(old);
|
HAL_DISABLE_INTERRUPTS(old);
|
HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_ETH);
|
HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_ETH);
|
HAL_RESTORE_INTERRUPTS(old);
|
HAL_RESTORE_INTERRUPTS(old);
|
...
|
...
|
|
|
|
|
|
|
|
|
HAL_INTERRUPT_MASK() causes the interrupt
|
HAL_INTERRUPT_MASK() causes the interrupt
|
associated with the given vector to be blocked.
|
associated with the given vector to be blocked.
|
|
|
|
|
|
|
HAL_INTERRUPT_UNMASK() causes the interrupt
|
HAL_INTERRUPT_UNMASK() causes the interrupt
|
associated with the given vector to be unblocked.
|
associated with the given vector to be unblocked.
|
|
|
|
|
|
|
HAL_INTERRUPT_ACKNOWLEDGE() acknowledges the
|
HAL_INTERRUPT_ACKNOWLEDGE() acknowledges the
|
current interrupt from the given vector. This is usually executed from
|
current interrupt from the given vector. This is usually executed from
|
the ISR for this vector when it is prepared to allow further
|
the ISR for this vector when it is prepared to allow further
|
interrupts. Most interrupt controllers need some form of acknowledge
|
interrupts. Most interrupt controllers need some form of acknowledge
|
action before the next interrupt is allowed through. Executing this
|
action before the next interrupt is allowed through. Executing this
|
macro may cause another interrupt to be delivered. Whether this
|
macro may cause another interrupt to be delivered. Whether this
|
interrupts the current code depends on the state of the CPU interrupt
|
interrupts the current code depends on the state of the CPU interrupt
|
mask.
|
mask.
|
|
|
|
|
|
|
HAL_INTERRUPT_CONFIGURE() provides
|
HAL_INTERRUPT_CONFIGURE() provides
|
control over how an interrupt signal is detected. The arguments
|
control over how an interrupt signal is detected. The arguments
|
are:
|
are:
|
|
|
|
|
|
|
vector
|
vector
|
|
|
The interrupt vector to be configured.
|
The interrupt vector to be configured.
|
|
|
|
|
|
|
|
|
level
|
level
|
|
|
|
|
Set to true if the interrupt is detected by
|
Set to true if the interrupt is detected by
|
level, and false if it is edge triggered.
|
level, and false if it is edge triggered.
|
|
|
|
|
|
|
|
|
|
|
up
|
up
|
|
|
|
|
If the interrupt is set to level detect, then if this is
|
If the interrupt is set to level detect, then if this is
|
true it is detected by a high signal level,
|
true it is detected by a high signal level,
|
and if false by a low signal level. If the
|
and if false by a low signal level. If the
|
interrupt is set to edge triggered, then if this is
|
interrupt is set to edge triggered, then if this is
|
true it is triggered by a rising edge and if
|
true it is triggered by a rising edge and if
|
false by a falling edge.
|
false by a falling edge.
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL_INTERRUPT_SET_LEVEL() provides control over
|
HAL_INTERRUPT_SET_LEVEL() provides control over
|
the hardware priority of the interrupt. The arguments are:
|
the hardware priority of the interrupt. The arguments are:
|
|
|
|
|
|
|
|
|
vector
|
vector
|
|
|
The interrupt whose level is to be set.
|
The interrupt whose level is to be set.
|
|
|
|
|
|
|
|
|
level
|
level
|
|
|
|
|
The priority level to which the interrupt is to set. In some
|
The priority level to which the interrupt is to set. In some
|
architectures the masking of an interrupt is achieved by
|
architectures the masking of an interrupt is achieved by
|
changing its priority level. Hence this function,
|
changing its priority level. Hence this function,
|
HAL_INTERRUPT_MASK() and
|
HAL_INTERRUPT_MASK() and
|
HAL_INTERRUPT_UNMASK() may interfere with
|
HAL_INTERRUPT_UNMASK() may interfere with
|
each other.
|
each other.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Clock control
|
Clock control
|
|
|
|
|
HAL_CLOCK_INITIALIZE( period )
|
HAL_CLOCK_INITIALIZE( period )
|
HAL_CLOCK_RESET( vector, period )
|
HAL_CLOCK_RESET( vector, period )
|
HAL_CLOCK_READ( pvalue )
|
HAL_CLOCK_READ( pvalue )
|
|
|
|
|
|
|
These macros provide control over a clock or timer device that may be
|
These macros provide control over a clock or timer device that may be
|
used by the kernel to provide time-out, delay and scheduling
|
used by the kernel to provide time-out, delay and scheduling
|
services. The clock is assumed to be implemented by some form of
|
services. The clock is assumed to be implemented by some form of
|
counter that is incremented or decremented by some external source and
|
counter that is incremented or decremented by some external source and
|
which raises an interrupt when it reaches a predetermined value.
|
which raises an interrupt when it reaches a predetermined value.
|
|
|
|
|
|
|
HAL_CLOCK_INITIALIZE() initializes the timer
|
HAL_CLOCK_INITIALIZE() initializes the timer
|
device to interrupt at the given period. The period is essentially the
|
device to interrupt at the given period. The period is essentially the
|
value used to initialize the timer counter and must be calculated from
|
value used to initialize the timer counter and must be calculated from
|
the timer frequency and the desired interrupt rate. The timer device
|
the timer frequency and the desired interrupt rate. The timer device
|
should generate an interrupt every period cycles.
|
should generate an interrupt every period cycles.
|
|
|
|
|
|
|
HAL_CLOCK_RESET() re-initializes the timer to
|
HAL_CLOCK_RESET() re-initializes the timer to
|
provoke the next interrupt. This macro is only really necessary when
|
provoke the next interrupt. This macro is only really necessary when
|
the timer device needs to be reset in some way after each interrupt.
|
the timer device needs to be reset in some way after each interrupt.
|
|
|
|
|
|
|
HAL_CLOCK_READ() reads the current value of the
|
HAL_CLOCK_READ() reads the current value of the
|
timer counter and puts the value in the location pointed to by
|
timer counter and puts the value in the location pointed to by
|
pvalue. The value stored will always be the
|
pvalue. The value stored will always be the
|
number of timer cycles since the last interrupt, and hence ranges
|
number of timer cycles since the last interrupt, and hence ranges
|
between zero and the initial period value. If this is a count-down
|
between zero and the initial period value. If this is a count-down
|
cyclic timer, some arithmetic may be necessary to generate this value.
|
cyclic timer, some arithmetic may be necessary to generate this value.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Microsecond Delay
|
Microsecond Delay
|
|
|
|
|
HAL_DELAY_US(us)
|
HAL_DELAY_US(us)
|
|
|
|
|
|
|
This is an optional definition. If defined the macro implements a busy
|
This is an optional definition. If defined the macro implements a busy
|
loop delay for the given number of microseconds. This is usually
|
loop delay for the given number of microseconds. This is usually
|
implemented by waiting for the required number of hardware timer ticks
|
implemented by waiting for the required number of hardware timer ticks
|
to pass.
|
to pass.
|
|
|
|
|
|
|
This operation should normally be used when a very short delay is
|
This operation should normally be used when a very short delay is
|
needed when controlling hardware, programming FLASH devices and similar
|
needed when controlling hardware, programming FLASH devices and similar
|
situations where a wait/timeout loop would otherwise be used. Since it
|
situations where a wait/timeout loop would otherwise be used. Since it
|
may disable interrupts, and is implemented by busy waiting, it should
|
may disable interrupts, and is implemented by busy waiting, it should
|
not be used in code that is sensitive to interrupt or context switch
|
not be used in code that is sensitive to interrupt or context switch
|
latencies.
|
latencies.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL I/O
|
HAL I/O
|
|
|
|
|
This section contains definitions for supporting access
|
This section contains definitions for supporting access
|
to device control registers in an architecture neutral
|
to device control registers in an architecture neutral
|
fashion.
|
fashion.
|
|
|
|
|
|
|
These definitions are normally found in the header file
|
These definitions are normally found in the header file
|
cyg/hal/hal_io.h. This file itself contains
|
cyg/hal/hal_io.h. This file itself contains
|
macros that are generic to the architecture. If there are variant or
|
macros that are generic to the architecture. If there are variant or
|
platform specific IO access macros then these will be found in
|
platform specific IO access macros then these will be found in
|
cyg/hal/var_io.h and
|
cyg/hal/var_io.h and
|
cyg/hal/plf_io.h in the variant or platform HALs
|
cyg/hal/plf_io.h in the variant or platform HALs
|
respectively. These files are include automatically by this header, so
|
respectively. These files are include automatically by this header, so
|
need not be included explicitly.
|
need not be included explicitly.
|
|
|
|
|
|
|
This header (or more likely cyg/hal/plf_io.h) also
|
This header (or more likely cyg/hal/plf_io.h) also
|
defines the PCI access macros. For more information on these see
|
defines the PCI access macros. For more information on these see
|
linkend="pci-library-reference">.
|
linkend="pci-library-reference">.
|
|
|
|
|
|
|
|
|
|
|
Register address
|
Register address
|
|
|
|
|
HAL_IO_REGISTER
|
HAL_IO_REGISTER
|
|
|
|
|
|
|
This type is used to store the address of an I/O register. It will
|
This type is used to store the address of an I/O register. It will
|
normally be a memory address, an integer port address or an offset
|
normally be a memory address, an integer port address or an offset
|
into an I/O space. More complex architectures may need to code an
|
into an I/O space. More complex architectures may need to code an
|
address space plus offset pair into a single word, or may represent it
|
address space plus offset pair into a single word, or may represent it
|
as a structure.
|
as a structure.
|
|
|
|
|
|
|
Values of variables and constants of this type will usually be
|
Values of variables and constants of this type will usually be
|
supplied by configuration mechanisms or in target specific headers.
|
supplied by configuration mechanisms or in target specific headers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Register read
|
Register read
|
|
|
|
|
HAL_READ_XXX( register, value )
|
HAL_READ_XXX( register, value )
|
HAL_READ_XXX_VECTOR( register, buffer, count, stride )
|
HAL_READ_XXX_VECTOR( register, buffer, count, stride )
|
|
|
|
|
|
|
These macros support the reading of I/O registers in various
|
These macros support the reading of I/O registers in various
|
sizes. The XXX component of the name may be
|
sizes. The XXX component of the name may be
|
UINT8, UINT16,
|
UINT8, UINT16,
|
UINT32.
|
UINT32.
|
|
|
|
|
|
|
HAL_READ_XXX() reads the appropriately sized
|
HAL_READ_XXX() reads the appropriately sized
|
value from the register and stores it in the variable passed as the
|
value from the register and stores it in the variable passed as the
|
second argument.
|
second argument.
|
|
|
|
|
|
|
HAL_READ_XXX_VECTOR() reads
|
HAL_READ_XXX_VECTOR() reads
|
count values of the appropriate size into
|
count values of the appropriate size into
|
buffer. The stride
|
buffer. The stride
|
controls how the pointer advances through the register space. A stride
|
controls how the pointer advances through the register space. A stride
|
of zero will read the same register repeatedly, and a stride of one
|
of zero will read the same register repeatedly, and a stride of one
|
will read adjacent registers of the given size. Greater strides will
|
will read adjacent registers of the given size. Greater strides will
|
step by larger amounts, to allow for sparsely mapped registers for
|
step by larger amounts, to allow for sparsely mapped registers for
|
example.
|
example.
|
|
|
|
|
|
|
|
|
|
|
Register write
|
Register write
|
|
|
|
|
HAL_WRITE_XXX( register, value )
|
HAL_WRITE_XXX( register, value )
|
HAL_WRITE_XXX_VECTOR( register, buffer,count, stride )
|
HAL_WRITE_XXX_VECTOR( register, buffer,count, stride )
|
|
|
|
|
|
|
These macros support the writing of I/O registers in various
|
These macros support the writing of I/O registers in various
|
sizes. The XXX component of the name may be
|
sizes. The XXX component of the name may be
|
UINT8, UINT16,
|
UINT8, UINT16,
|
UINT32.
|
UINT32.
|
|
|
|
|
|
|
HAL_WRITE_XXX() writes
|
HAL_WRITE_XXX() writes
|
the appropriately sized value from the variable passed as the second argument
|
the appropriately sized value from the variable passed as the second argument
|
stored it in the register.
|
stored it in the register.
|
HAL_WRITE_XXX_VECTOR() writes
|
HAL_WRITE_XXX_VECTOR() writes
|
count values of the appropriate size from
|
count values of the appropriate size from
|
buffer. The stride controls
|
buffer. The stride controls
|
how the pointer advances through the register space. A stride of
|
how the pointer advances through the register space. A stride of
|
zero will write the same register repeatedly, and a stride of one
|
zero will write the same register repeatedly, and a stride of one
|
will write adjacent registers of the given size. Greater strides
|
will write adjacent registers of the given size. Greater strides
|
will step by larger amounts, to allow for sparsely mapped registers
|
will step by larger amounts, to allow for sparsely mapped registers
|
for example.
|
for example.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Cache Control
|
Cache Control
|
|
|
This section contains definitions for supporting control
|
This section contains definitions for supporting control
|
of the caches on the CPU.
|
of the caches on the CPU.
|
|
|
|
|
|
|
These definitions are usually found in the header file
|
These definitions are usually found in the header file
|
cyg/hal/hal_cache.h. This file may be defined in
|
cyg/hal/hal_cache.h. This file may be defined in
|
the architecture, variant or platform HAL, depending on where the
|
the architecture, variant or platform HAL, depending on where the
|
caches are implemented for the target. Often there will be a generic
|
caches are implemented for the target. Often there will be a generic
|
implementation of the cache control macros in the architecture HAL
|
implementation of the cache control macros in the architecture HAL
|
with the ability to override or undefine them in the variant or
|
with the ability to override or undefine them in the variant or
|
platform HAL. Even when the implementation of the cache macros is in
|
platform HAL. Even when the implementation of the cache macros is in
|
the architecture HAL, the cache dimensions will be defined in the
|
the architecture HAL, the cache dimensions will be defined in the
|
variant or platform HAL. As with other files, the variant or platform
|
variant or platform HAL. As with other files, the variant or platform
|
specific definitions are usually found in
|
specific definitions are usually found in
|
cyg/hal/var_cache.h and
|
cyg/hal/var_cache.h and
|
cyg/hal/plf_cache.h respectively. These files
|
cyg/hal/plf_cache.h respectively. These files
|
are include automatically by this header, so need not be included
|
are include automatically by this header, so need not be included
|
explicitly.
|
explicitly.
|
|
|
|
|
|
|
There are versions of the macros defined here for both the Data and
|
There are versions of the macros defined here for both the Data and
|
Instruction caches. these are distinguished by the use of either
|
Instruction caches. these are distinguished by the use of either
|
DCACHE or ICACHE in the macro
|
DCACHE or ICACHE in the macro
|
names. Some architectures have a unified cache, where both data and
|
names. Some architectures have a unified cache, where both data and
|
instruction share the same cache. In these cases the control macros
|
instruction share the same cache. In these cases the control macros
|
use UCACHE and the DCACHE and
|
use UCACHE and the DCACHE and
|
ICACHE macros will just be calls to the
|
ICACHE macros will just be calls to the
|
UCACHE version. In the following descriptions,
|
UCACHE version. In the following descriptions,
|
XCACHE is used to stand for any of these. Where
|
XCACHE is used to stand for any of these. Where
|
there are issues specific to a particular cache, this will be
|
there are issues specific to a particular cache, this will be
|
explained in the text.
|
explained in the text.
|
|
|
|
|
|
|
There might be target specific restrictions on the use of some of the
|
There might be target specific restrictions on the use of some of the
|
macros which it is the user's responsibility to comply with. Such
|
macros which it is the user's responsibility to comply with. Such
|
restrictions are documented in the header file with the macro
|
restrictions are documented in the header file with the macro
|
definition.
|
definition.
|
|
|
|
|
|
|
Note that destructive cache macros should be used with caution.
|
Note that destructive cache macros should be used with caution.
|
Preceding a cache invalidation with a cache synchronization is not
|
Preceding a cache invalidation with a cache synchronization is not
|
safe in itself since an interrupt may happen after the synchronization
|
safe in itself since an interrupt may happen after the synchronization
|
but before the invalidation. This might cause the state of dirty data
|
but before the invalidation. This might cause the state of dirty data
|
lines created during the interrupt to be lost.
|
lines created during the interrupt to be lost.
|
|
|
|
|
|
|
Depending on the architecture's capabilities, it may be possible to
|
Depending on the architecture's capabilities, it may be possible to
|
temporarily disable the cache while doing the synchronization and
|
temporarily disable the cache while doing the synchronization and
|
invalidation which solves the problem (no new data would be cached
|
invalidation which solves the problem (no new data would be cached
|
during an interrupt). Otherwise it is necessary to disable interrupts
|
during an interrupt). Otherwise it is necessary to disable interrupts
|
while manipulating the cache which may take a long time.
|
while manipulating the cache which may take a long time.
|
|
|
|
|
|
|
Some platform HALs now support a pair of cache state query
|
Some platform HALs now support a pair of cache state query
|
macros: HAL_ICACHE_IS_ENABLED( x ) and
|
macros: HAL_ICACHE_IS_ENABLED( x ) and
|
HAL_DCACHE_IS_ENABLED( x ) which set the argument
|
HAL_DCACHE_IS_ENABLED( x ) which set the argument
|
to true if the instruction or data cache is enabled,
|
to true if the instruction or data cache is enabled,
|
respectively. Like most cache control macros, these are optional,
|
respectively. Like most cache control macros, these are optional,
|
because the capabilities of different targets and boards can vary
|
because the capabilities of different targets and boards can vary
|
considerably. Code which uses them, if it is to be considered
|
considerably. Code which uses them, if it is to be considered
|
portable, should test for their existence first by means of
|
portable, should test for their existence first by means of
|
#ifdef. Be sure to include
|
#ifdef. Be sure to include
|
<cyg/hal/hal_cache.h> in order to do this
|
<cyg/hal/hal_cache.h> in order to do this
|
test and (maybe) use the macros.
|
test and (maybe) use the macros.
|
|
|
|
|
|
|
|
|
|
|
Cache Dimensions
|
Cache Dimensions
|
|
|
|
|
HAL_XCACHE_SIZE
|
HAL_XCACHE_SIZE
|
HAL_XCACHE_LINE_SIZE
|
HAL_XCACHE_LINE_SIZE
|
HAL_XCACHE_WAYS
|
HAL_XCACHE_WAYS
|
HAL_XCACHE_SETS
|
HAL_XCACHE_SETS
|
|
|
|
|
These macros define the size and dimensions of the Instruction
|
These macros define the size and dimensions of the Instruction
|
and Data caches.
|
and Data caches.
|
|
|
|
|
|
|
|
|
HAL_XCACHE_SIZE
|
HAL_XCACHE_SIZE
|
|
|
Defines the total size of the cache in bytes.
|
Defines the total size of the cache in bytes.
|
|
|
|
|
|
|
|
|
HAL_XCACHE_LINE_SIZE
|
HAL_XCACHE_LINE_SIZE
|
|
|
Defines the cache line size in bytes.
|
Defines the cache line size in bytes.
|
|
|
|
|
|
|
|
|
HAL_XCACHE_WAYS
|
HAL_XCACHE_WAYS
|
|
|
|
|
Defines the number of ways in each set and defines its level
|
Defines the number of ways in each set and defines its level
|
of associativity. This would be 1 for a direct mapped
|
of associativity. This would be 1 for a direct mapped
|
cache, 2 for a 2-way cache, 4 for 4-way and so on.
|
cache, 2 for a 2-way cache, 4 for 4-way and so on.
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_SETS
|
HAL_XCACHE_SETS
|
|
|
|
|
Defines the number of sets in the cache, and is calculated from
|
Defines the number of sets in the cache, and is calculated from
|
the previous values.
|
the previous values.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Global Cache Control
|
Global Cache Control
|
|
|
|
|
HAL_XCACHE_ENABLE()
|
HAL_XCACHE_ENABLE()
|
HAL_XCACHE_DISABLE()
|
HAL_XCACHE_DISABLE()
|
HAL_XCACHE_INVALIDATE_ALL()
|
HAL_XCACHE_INVALIDATE_ALL()
|
HAL_XCACHE_SYNC()
|
HAL_XCACHE_SYNC()
|
HAL_XCACHE_BURST_SIZE( size )
|
HAL_XCACHE_BURST_SIZE( size )
|
HAL_DCACHE_WRITE_MODE( mode )
|
HAL_DCACHE_WRITE_MODE( mode )
|
HAL_XCACHE_LOCK( base, size )
|
HAL_XCACHE_LOCK( base, size )
|
HAL_XCACHE_UNLOCK( base, size )
|
HAL_XCACHE_UNLOCK( base, size )
|
HAL_XCACHE_UNLOCK_ALL()
|
HAL_XCACHE_UNLOCK_ALL()
|
|
|
|
|
|
|
These macros affect the state of the entire cache, or a large part of
|
These macros affect the state of the entire cache, or a large part of
|
it.
|
it.
|
|
|
|
|
|
|
|
|
HAL_XCACHE_ENABLE() and HAL_XCACHE_DISABLE()
|
HAL_XCACHE_ENABLE() and HAL_XCACHE_DISABLE()
|
|
|
Enable and disable the cache.
|
Enable and disable the cache.
|
|
|
|
|
|
|
|
|
HAL_XCACHE_INVALIDATE_ALL()
|
HAL_XCACHE_INVALIDATE_ALL()
|
|
|
|
|
Causes the entire contents of the cache to be invalidated.
|
Causes the entire contents of the cache to be invalidated.
|
Depending on the hardware, this may require the cache to be disabled
|
Depending on the hardware, this may require the cache to be disabled
|
during the invalidation process. If so, the implementation must
|
during the invalidation process. If so, the implementation must
|
use HAL_XCACHE_IS_ENABLED() to save and
|
use HAL_XCACHE_IS_ENABLED() to save and
|
restore the previous state.
|
restore the previous state.
|
|
|
|
|
|
|
If this macro is called after
|
If this macro is called after
|
HAL_XCACHE_SYNC() with the intention of clearing
|
HAL_XCACHE_SYNC() with the intention of clearing
|
the cache (invalidating the cache after writing dirty data back to
|
the cache (invalidating the cache after writing dirty data back to
|
memory), you must prevent interrupts from happening between the two
|
memory), you must prevent interrupts from happening between the two
|
calls:
|
calls:
|
|
|
|
|
...
|
...
|
HAL_DISABLE_INTERRUPTS(old);
|
HAL_DISABLE_INTERRUPTS(old);
|
HAL_XCACHE_SYNC();
|
HAL_XCACHE_SYNC();
|
HAL_XCACHE_INVALIDATE_ALL();
|
HAL_XCACHE_INVALIDATE_ALL();
|
HAL_RESTORE_INTERRUPTS(old);
|
HAL_RESTORE_INTERRUPTS(old);
|
...
|
...
|
|
|
|
|
Since the operation may take a very long time, real-time
|
Since the operation may take a very long time, real-time
|
responsiveness could be affected, so only do this when it is
|
responsiveness could be affected, so only do this when it is
|
absolutely required and you know the delay will not interfere
|
absolutely required and you know the delay will not interfere
|
with the operation of drivers or the application.
|
with the operation of drivers or the application.
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_SYNC()
|
HAL_XCACHE_SYNC()
|
|
|
|
|
Causes the contents of the cache to be brought into synchronization
|
Causes the contents of the cache to be brought into synchronization
|
with the contents of memory. In some implementations this may be
|
with the contents of memory. In some implementations this may be
|
equivalent to HAL_XCACHE_INVALIDATE_ALL().
|
equivalent to HAL_XCACHE_INVALIDATE_ALL().
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_BURST_SIZE()
|
HAL_XCACHE_BURST_SIZE()
|
|
|
|
|
Allows the size of cache to/from memory bursts to
|
Allows the size of cache to/from memory bursts to
|
be controlled. This macro will only be defined if this functionality
|
be controlled. This macro will only be defined if this functionality
|
is available.
|
is available.
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_WRITE_MODE()
|
HAL_DCACHE_WRITE_MODE()
|
|
|
|
|
Controls the way in which data cache lines are written back to
|
Controls the way in which data cache lines are written back to
|
memory. There will be definitions for the possible
|
memory. There will be definitions for the possible
|
modes. Typical definitions are
|
modes. Typical definitions are
|
HAL_DCACHE_WRITEBACK_MODE and
|
HAL_DCACHE_WRITEBACK_MODE and
|
HAL_DCACHE_WRITETHRU_MODE. This macro will
|
HAL_DCACHE_WRITETHRU_MODE. This macro will
|
only be defined if this functionality is available.
|
only be defined if this functionality is available.
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_LOCK()
|
HAL_XCACHE_LOCK()
|
|
|
|
|
Causes data to be locked into the cache. The base and size
|
Causes data to be locked into the cache. The base and size
|
arguments define the memory region that will be locked into the
|
arguments define the memory region that will be locked into the
|
cache. It is architecture dependent whether more than one locked
|
cache. It is architecture dependent whether more than one locked
|
region is allowed at any one time, and whether this operation
|
region is allowed at any one time, and whether this operation
|
causes the cache to cease acting as a cache for addresses
|
causes the cache to cease acting as a cache for addresses
|
outside the region during the duration of the lock. This macro
|
outside the region during the duration of the lock. This macro
|
will only be defined if this functionality is available.
|
will only be defined if this functionality is available.
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_UNLOCK()
|
HAL_XCACHE_UNLOCK()
|
|
|
|
|
Cancels the locking of the memory region given. This should
|
Cancels the locking of the memory region given. This should
|
normally correspond to a region supplied in a matching lock
|
normally correspond to a region supplied in a matching lock
|
call. This macro will only be defined if this functionality is
|
call. This macro will only be defined if this functionality is
|
available.
|
available.
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_UNLOCK_ALL()
|
HAL_XCACHE_UNLOCK_ALL()
|
|
|
|
|
Cancels all existing locked memory regions. This may be required
|
Cancels all existing locked memory regions. This may be required
|
as part of the cache initialization on some architectures. This
|
as part of the cache initialization on some architectures. This
|
macro will only be defined if this functionality is available.
|
macro will only be defined if this functionality is available.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Cache Line Control
|
Cache Line Control
|
|
|
|
|
HAL_DCACHE_ALLOCATE( base , size )
|
HAL_DCACHE_ALLOCATE( base , size )
|
HAL_DCACHE_FLUSH( base , size )
|
HAL_DCACHE_FLUSH( base , size )
|
HAL_XCACHE_INVALIDATE( base , size )
|
HAL_XCACHE_INVALIDATE( base , size )
|
HAL_DCACHE_STORE( base , size )
|
HAL_DCACHE_STORE( base , size )
|
HAL_DCACHE_READ_HINT( base , size )
|
HAL_DCACHE_READ_HINT( base , size )
|
HAL_DCACHE_WRITE_HINT( base , size )
|
HAL_DCACHE_WRITE_HINT( base , size )
|
HAL_DCACHE_ZERO( base , size )
|
HAL_DCACHE_ZERO( base , size )
|
|
|
|
|
|
|
All of these macros apply a cache operation to all cache lines that
|
All of these macros apply a cache operation to all cache lines that
|
match the memory address region defined by the base and size
|
match the memory address region defined by the base and size
|
arguments. These macros will only be defined if the described
|
arguments. These macros will only be defined if the described
|
functionality is available. Also, it is not guaranteed that the cache
|
functionality is available. Also, it is not guaranteed that the cache
|
function will only be applied to just the described regions, in some
|
function will only be applied to just the described regions, in some
|
architectures it may be applied to the whole cache.
|
architectures it may be applied to the whole cache.
|
|
|
|
|
|
|
|
|
HAL_DCACHE_ALLOCATE()
|
HAL_DCACHE_ALLOCATE()
|
|
|
|
|
Allocates lines in the cache for the given region without
|
Allocates lines in the cache for the given region without
|
reading their contents from memory, hence the contents of the lines
|
reading their contents from memory, hence the contents of the lines
|
is undefined. This is useful for preallocating lines which are to
|
is undefined. This is useful for preallocating lines which are to
|
be completely overwritten, for example in a block copy
|
be completely overwritten, for example in a block copy
|
operation.
|
operation.
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_FLUSH()
|
HAL_DCACHE_FLUSH()
|
|
|
|
|
Invalidates all cache lines in the region after writing any
|
Invalidates all cache lines in the region after writing any
|
dirty lines to memory.
|
dirty lines to memory.
|
|
|
|
|
|
|
|
|
|
|
HAL_XCACHE_INVALIDATE()
|
HAL_XCACHE_INVALIDATE()
|
|
|
|
|
Invalidates all cache lines in the region. Any dirty lines
|
Invalidates all cache lines in the region. Any dirty lines
|
are invalidated without being written to memory.
|
are invalidated without being written to memory.
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_STORE()
|
HAL_DCACHE_STORE()
|
|
|
|
|
Writes all dirty lines in the region to memory, but does not
|
Writes all dirty lines in the region to memory, but does not
|
invalidate any lines.
|
invalidate any lines.
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_READ_HINT()
|
HAL_DCACHE_READ_HINT()
|
|
|
|
|
Hints to the cache that the region is going to be read from
|
Hints to the cache that the region is going to be read from
|
in the near future. This may cause the region to be speculatively
|
in the near future. This may cause the region to be speculatively
|
read into the cache.
|
read into the cache.
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_WRITE_HINT()
|
HAL_DCACHE_WRITE_HINT()
|
|
|
|
|
Hints to the cache that the region is going to be written
|
Hints to the cache that the region is going to be written
|
to in the near future. This may have the identical behavior to
|
to in the near future. This may have the identical behavior to
|
HAL_DCACHE_READ_HINT().
|
HAL_DCACHE_READ_HINT().
|
|
|
|
|
|
|
|
|
|
|
HAL_DCACHE_ZERO()
|
HAL_DCACHE_ZERO()
|
|
|
|
|
Allocates and zeroes lines in the cache for the given
|
Allocates and zeroes lines in the cache for the given
|
region without reading memory. This is useful if a large area of
|
region without reading memory. This is useful if a large area of
|
memory is to be cleared.
|
memory is to be cleared.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Linker Scripts
|
Linker Scripts
|
|
|
|
|
When an eCos application is linked it must be done under the control
|
When an eCos application is linked it must be done under the control
|
of a linker script. This script defines the memory areas, addresses
|
of a linker script. This script defines the memory areas, addresses
|
and sized, into which the code and data are to be put, and allocates
|
and sized, into which the code and data are to be put, and allocates
|
the various sections generated by the compiler to these.
|
the various sections generated by the compiler to these.
|
|
|
|
|
|
|
The linker script actually used is in
|
The linker script actually used is in
|
lib/target.ld in the install directory. This is
|
lib/target.ld in the install directory. This is
|
actually manufactured out of two other files: a base linker script and
|
actually manufactured out of two other files: a base linker script and
|
an .ldi file that was generated by the memory
|
an .ldi file that was generated by the memory
|
layout tool.
|
layout tool.
|
|
|
|
|
|
|
The base linker script is usually supplied either by the architecture
|
The base linker script is usually supplied either by the architecture
|
HAL or the variant HAL. It consists of a set of linker script
|
HAL or the variant HAL. It consists of a set of linker script
|
fragments, in the form of C preprocessor macros, that define the major
|
fragments, in the form of C preprocessor macros, that define the major
|
output sections to be generated by the link operation. The
|
output sections to be generated by the link operation. The
|
.ldi file, which is #include'ed
|
.ldi file, which is #include'ed
|
by the base linker script, uses these macro definitions to assign the
|
by the base linker script, uses these macro definitions to assign the
|
output sections to the required memory areas and link addresses.
|
output sections to the required memory areas and link addresses.
|
|
|
|
|
|
|
The .ldi file is supplied by the platform HAL, and
|
The .ldi file is supplied by the platform HAL, and
|
contains knowledge of the memory layout of the target platform. These
|
contains knowledge of the memory layout of the target platform. These
|
files generally conform to a standard naming convention, each file
|
files generally conform to a standard naming convention, each file
|
being of the form:
|
being of the form:
|
|
|
|
|
pkgconf/mlt_<architecture>_<variant>_<platform>_<startup>.ldi
|
pkgconf/mlt_<architecture>_<variant>_<platform>_<startup>.ldi
|
|
|
|
|
where <architecture>,
|
where <architecture>,
|
<variant> and
|
<variant> and
|
<platform> are the respective HAL package
|
<platform> are the respective HAL package
|
names and <startup> is the startup type which
|
names and <startup> is the startup type which
|
is usually one of ROM, RAM or
|
is usually one of ROM, RAM or
|
ROMRAM.
|
ROMRAM.
|
|
|
|
|
|
|
In addition to the .ldi file, there is also a
|
In addition to the .ldi file, there is also a
|
congruously name .h file. This may be used by the
|
congruously name .h file. This may be used by the
|
application to access information defined in the
|
application to access information defined in the
|
.ldi file. Specifically it contains the memory
|
.ldi file. Specifically it contains the memory
|
layout defined there, together with any additional section names
|
layout defined there, together with any additional section names
|
defined by the user. Examples of the latter are heap areas or PCI bus
|
defined by the user. Examples of the latter are heap areas or PCI bus
|
memory access windows.
|
memory access windows.
|
|
|
|
|
|
|
The .ldi is manufactured by the Memory
|
The .ldi is manufactured by the Memory
|
Layout Tool (MLT). The MLT saves the memory
|
Layout Tool (MLT). The MLT saves the memory
|
configuration into a file named
|
configuration into a file named
|
|
|
|
|
include/pkgconf/mlt_<architecture>_<variant>_<platform>_<startup>.mlt
|
include/pkgconf/mlt_<architecture>_<variant>_<platform>_<startup>.mlt
|
|
|
|
|
in the platform HAL. This file is used by the
|
in the platform HAL. This file is used by the
|
MLT to manufacture both the
|
MLT to manufacture both the
|
.ldi and .h files. Users should
|
.ldi and .h files. Users should
|
beware that direct edits the either of these files may be overwritten
|
beware that direct edits the either of these files may be overwritten
|
if the MLT is run and regenerates them from the
|
if the MLT is run and regenerates them from the
|
.mlt file.
|
.mlt file.
|
|
|
|
|
|
|
The names of the .ldi and .h
|
The names of the .ldi and .h
|
files are defined by macro definitions in
|
files are defined by macro definitions in
|
pkgconf/system.h. These are
|
pkgconf/system.h. These are
|
CYGHWR_MEMORY_LAYOUT_LDI and
|
CYGHWR_MEMORY_LAYOUT_LDI and
|
CYGHWR_MEMORY_LAYOUT_H respectively. While there
|
CYGHWR_MEMORY_LAYOUT_H respectively. While there
|
will be little need for the application to refer to the
|
will be little need for the application to refer to the
|
.ldi file directly, it may include the
|
.ldi file directly, it may include the
|
.h file as follows:
|
.h file as follows:
|
|
|
|
|
|
|
#include CYGHWR_MEMORY_LAYOUT_H
|
#include CYGHWR_MEMORY_LAYOUT_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Diagnostic Support
|
Diagnostic Support
|
|
|
|
|
The HAL provides support for low level diagnostic IO. This is
|
The HAL provides support for low level diagnostic IO. This is
|
particularly useful during early development as an aid to bringing up
|
particularly useful during early development as an aid to bringing up
|
a new platform. Usually this diagnostic channel is a UART or some
|
a new platform. Usually this diagnostic channel is a UART or some
|
other serial IO device, but it may equally be a a memory
|
other serial IO device, but it may equally be a a memory
|
buffer, a simulator supported output channel, a ROM emulator virtual
|
buffer, a simulator supported output channel, a ROM emulator virtual
|
UART, and LCD panel, a memory mapped video buffer or any other output
|
UART, and LCD panel, a memory mapped video buffer or any other output
|
device.
|
device.
|
|
|
|
|
|
|
HAL_DIAG_INIT() performs any initialization
|
HAL_DIAG_INIT() performs any initialization
|
required on the device being used to generate diagnostic output. This
|
required on the device being used to generate diagnostic output. This
|
may include, for a UART, setting baud rate, and stop, parity and
|
may include, for a UART, setting baud rate, and stop, parity and
|
character bits. For other devices it may include initializing a
|
character bits. For other devices it may include initializing a
|
controller or establishing contact with a remote device.
|
controller or establishing contact with a remote device.
|
|
|
|
|
|
|
HAL_DIAG_WRITE_CHAR(c) writes
|
HAL_DIAG_WRITE_CHAR(c) writes
|
the character supplied to the diagnostic output device.
|
the character supplied to the diagnostic output device.
|
|
|
|
|
|
|
HAL_DIAG_READ_CHAR(c) reads a character from the
|
HAL_DIAG_READ_CHAR(c) reads a character from the
|
diagnostic device into the supplied variable. This is not supported
|
diagnostic device into the supplied variable. This is not supported
|
for all diagnostic devices.
|
for all diagnostic devices.
|
|
|
|
|
|
|
These macros are defined in the header file
|
These macros are defined in the header file
|
cyg/hal/hal_diag.h. This file is usually supplied
|
cyg/hal/hal_diag.h. This file is usually supplied
|
by the variant or platform HAL, depending on where the IO device being
|
by the variant or platform HAL, depending on where the IO device being
|
used is located. For example for on-chip UARTs it would be in the
|
used is located. For example for on-chip UARTs it would be in the
|
variant HAL, but for a board-level LCD panel it would be in the
|
variant HAL, but for a board-level LCD panel it would be in the
|
platform HAL.
|
platform HAL.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SMP Support
|
SMP Support
|
|
|
|
|
eCos contains support for limited Symmetric Multi-Processing
|
eCos contains support for limited Symmetric Multi-Processing
|
(SMP). This is only available on selected architectures and platforms.
|
(SMP). This is only available on selected architectures and platforms.
|
|
|
|
|
|
|
Target Hardware Limitations
|
Target Hardware Limitations
|
|
|
|
|
To allow a reasonable implementation of SMP, and to reduce the
|
To allow a reasonable implementation of SMP, and to reduce the
|
disruption to the existing source base, a number of assumptions have
|
disruption to the existing source base, a number of assumptions have
|
been made about the features of the target hardware.
|
been made about the features of the target hardware.
|
|
|
|
|
|
|
|
|
|
|
Modest multiprocessing. The typical number of CPUs supported is two
|
Modest multiprocessing. The typical number of CPUs supported is two
|
to four, with an upper limit around eight. While there are no
|
to four, with an upper limit around eight. While there are no
|
inherent limits in the code, hardware and algorithmic limitations
|
inherent limits in the code, hardware and algorithmic limitations
|
will probably become significant beyond this point.
|
will probably become significant beyond this point.
|
|
|
|
|
|
|
|
|
|
|
SMP synchronization support. The hardware must supply a mechanism to
|
SMP synchronization support. The hardware must supply a mechanism to
|
allow software on two CPUs to synchronize. This is normally provided
|
allow software on two CPUs to synchronize. This is normally provided
|
as part of the instruction set in the form of test-and-set,
|
as part of the instruction set in the form of test-and-set,
|
compare-and-swap or load-link/store-conditional instructions. An
|
compare-and-swap or load-link/store-conditional instructions. An
|
alternative approach is the provision of hardware semaphore
|
alternative approach is the provision of hardware semaphore
|
registers which can be used to serialize implementations of these
|
registers which can be used to serialize implementations of these
|
operations. Whatever hardware facilities are available, they are
|
operations. Whatever hardware facilities are available, they are
|
used in eCos to implement spinlocks.
|
used in eCos to implement spinlocks.
|
|
|
|
|
|
|
|
|
|
|
Coherent caches. It is assumed that no extra effort will be required
|
Coherent caches. It is assumed that no extra effort will be required
|
to access shared memory from any processor. This means that either
|
to access shared memory from any processor. This means that either
|
there are no caches, they are shared by all processors, or are
|
there are no caches, they are shared by all processors, or are
|
maintained in a coherent state by the hardware. It would be too
|
maintained in a coherent state by the hardware. It would be too
|
disruptive to the eCos sources if every memory access had to be
|
disruptive to the eCos sources if every memory access had to be
|
bracketed by cache load/flush operations. Any hardware that requires
|
bracketed by cache load/flush operations. Any hardware that requires
|
this is not supported.
|
this is not supported.
|
|
|
|
|
|
|
|
|
|
|
Uniform addressing. It is assumed that all memory that is
|
Uniform addressing. It is assumed that all memory that is
|
shared between CPUs is addressed at the same location from all
|
shared between CPUs is addressed at the same location from all
|
CPUs. Like non-coherent caches, dealing with CPU-specific address
|
CPUs. Like non-coherent caches, dealing with CPU-specific address
|
translation is considered too disruptive to the eCos source
|
translation is considered too disruptive to the eCos source
|
base. This does not, however, preclude systems with non-uniform
|
base. This does not, however, preclude systems with non-uniform
|
access costs for different CPUs.
|
access costs for different CPUs.
|
|
|
|
|
|
|
|
|
|
|
Uniform device addressing. As with access to memory, it is assumed
|
Uniform device addressing. As with access to memory, it is assumed
|
that all devices are equally accessible to all CPUs. Since device
|
that all devices are equally accessible to all CPUs. Since device
|
access is often made from thread contexts, it is not possible to
|
access is often made from thread contexts, it is not possible to
|
restrict access to device control registers to certain CPUs, since
|
restrict access to device control registers to certain CPUs, since
|
there is currently no support for binding or migrating threads to CPUs.
|
there is currently no support for binding or migrating threads to CPUs.
|
|
|
|
|
|
|
|
|
|
|
Interrupt routing. The target hardware must have an interrupt
|
Interrupt routing. The target hardware must have an interrupt
|
controller that can route interrupts to specific CPUs. It is
|
controller that can route interrupts to specific CPUs. It is
|
acceptable for all interrupts to be delivered to just one CPU, or
|
acceptable for all interrupts to be delivered to just one CPU, or
|
for some interrupts to be bound to specific CPUs, or for some
|
for some interrupts to be bound to specific CPUs, or for some
|
interrupts to be local to each CPU. At present dynamic routing,
|
interrupts to be local to each CPU. At present dynamic routing,
|
where a different CPU may be chosen each time an interrupt is
|
where a different CPU may be chosen each time an interrupt is
|
delivered, is not supported. ECos cannot support hardware where all
|
delivered, is not supported. ECos cannot support hardware where all
|
interrupts are delivered to all CPUs simultaneously with the
|
interrupts are delivered to all CPUs simultaneously with the
|
expectation that software will resolve any conflicts.
|
expectation that software will resolve any conflicts.
|
|
|
|
|
|
|
|
|
|
|
Inter-CPU interrupts. A mechanism to allow one CPU to interrupt
|
Inter-CPU interrupts. A mechanism to allow one CPU to interrupt
|
another is needed. This is necessary so that events on one CPU can
|
another is needed. This is necessary so that events on one CPU can
|
cause rescheduling on other CPUs.
|
cause rescheduling on other CPUs.
|
|
|
|
|
|
|
|
|
|
|
CPU Identifiers. Code running on a CPU must be able to determine
|
CPU Identifiers. Code running on a CPU must be able to determine
|
which CPU it is running on. The CPU Id is usually provided either in
|
which CPU it is running on. The CPU Id is usually provided either in
|
a CPU status register, or in a register associated with the
|
a CPU status register, or in a register associated with the
|
inter-CPU interrupt delivery subsystem. ECos expects CPU Ids to be
|
inter-CPU interrupt delivery subsystem. ECos expects CPU Ids to be
|
small positive integers, although alternative representations, such
|
small positive integers, although alternative representations, such
|
as bitmaps, can be converted relatively easily. Complex mechanisms
|
as bitmaps, can be converted relatively easily. Complex mechanisms
|
for getting the CPU Id cannot be supported. Getting the CPU Id must
|
for getting the CPU Id cannot be supported. Getting the CPU Id must
|
be a cheap operation, since it is done often, and in performance
|
be a cheap operation, since it is done often, and in performance
|
critical places such as interrupt handlers and the scheduler.
|
critical places such as interrupt handlers and the scheduler.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL Support
|
HAL Support
|
|
|
|
|
SMP support in any platform depends on the HAL supplying the
|
SMP support in any platform depends on the HAL supplying the
|
appropriate operations. All HAL SMP support is defined in the
|
appropriate operations. All HAL SMP support is defined in the
|
cyg/hal/hal_smp.h header. Variant and platform
|
cyg/hal/hal_smp.h header. Variant and platform
|
specific definitions will be in cyg/hal/var_smp.h
|
specific definitions will be in cyg/hal/var_smp.h
|
and cyg/hal/plf_smp.h respectively. These files
|
and cyg/hal/plf_smp.h respectively. These files
|
are include automatically by this header, so need not be included
|
are include automatically by this header, so need not be included
|
explicitly.
|
explicitly.
|
|
|
|
|
|
|
SMP support falls into a number of functional groups.
|
SMP support falls into a number of functional groups.
|
|
|
|
|
|
|
CPU Control
|
CPU Control
|
|
|
|
|
This group consists of descriptive and control macros for managing the
|
This group consists of descriptive and control macros for managing the
|
CPUs in an SMP system.
|
CPUs in an SMP system.
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_TYPE
|
HAL_SMP_CPU_TYPE
|
|
|
|
|
A type that can contain a CPU id. A CPU id is
|
A type that can contain a CPU id. A CPU id is
|
usually a small integer that is used to index
|
usually a small integer that is used to index
|
arrays of variables that are managed on an
|
arrays of variables that are managed on an
|
per-CPU basis.
|
per-CPU basis.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_MAX
|
HAL_SMP_CPU_MAX
|
|
|
|
|
The maximum number of CPUs that can be
|
The maximum number of CPUs that can be
|
supported. This is used to provide the size of
|
supported. This is used to provide the size of
|
any arrays that have an element per CPU.
|
any arrays that have an element per CPU.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_COUNT()
|
HAL_SMP_CPU_COUNT()
|
|
|
|
|
Returns the number of CPUs currently
|
Returns the number of CPUs currently
|
operational. This may differ from
|
operational. This may differ from
|
HAL_SMP_CPU_MAX depending on the runtime
|
HAL_SMP_CPU_MAX depending on the runtime
|
environment.
|
environment.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_THIS()
|
HAL_SMP_CPU_THIS()
|
|
|
|
|
Returns the CPU id of the current CPU.
|
Returns the CPU id of the current CPU.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_NONE
|
HAL_SMP_CPU_NONE
|
|
|
|
|
A value that does not match any real CPU
|
A value that does not match any real CPU
|
id. This is uses where a CPU type variable
|
id. This is uses where a CPU type variable
|
must be set to a null value.
|
must be set to a null value.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_START( cpu )
|
HAL_SMP_CPU_START( cpu )
|
|
|
|
|
Starts the given CPU executing at a defined
|
Starts the given CPU executing at a defined
|
HAL entry point. After performing any HAL
|
HAL entry point. After performing any HAL
|
level initialization, the CPU calls up into
|
level initialization, the CPU calls up into
|
the kernel at cyg_kernel_cpu_startup().
|
the kernel at cyg_kernel_cpu_startup().
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_RESCHEDULE_INTERRUPT( cpu, wait )
|
HAL_SMP_CPU_RESCHEDULE_INTERRUPT( cpu, wait )
|
|
|
|
|
Sends the CPU a reschedule interrupt, and if
|
Sends the CPU a reschedule interrupt, and if
|
wait is non-zero, waits for an
|
wait is non-zero, waits for an
|
acknowledgment. The interrupted CPU should call
|
acknowledgment. The interrupted CPU should call
|
cyg_scheduler_set_need_reschedule() in its DSR to
|
cyg_scheduler_set_need_reschedule() in its DSR to
|
cause the reschedule to occur.
|
cause the reschedule to occur.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_CPU_TIMESLICE_INTERRUPT( cpu, wait )
|
HAL_SMP_CPU_TIMESLICE_INTERRUPT( cpu, wait )
|
|
|
|
|
Sends the CPU a timeslice interrupt, and if
|
Sends the CPU a timeslice interrupt, and if
|
wait is non-zero, waits for an
|
wait is non-zero, waits for an
|
acknowledgment. The interrupted CPU should call
|
acknowledgment. The interrupted CPU should call
|
cyg_scheduler_timeslice_cpu() to cause the
|
cyg_scheduler_timeslice_cpu() to cause the
|
timeslice event to be processed.
|
timeslice event to be processed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Test-and-set Support
|
Test-and-set Support
|
|
|
|
|
Test-and-set is the foundation of the SMP synchronization
|
Test-and-set is the foundation of the SMP synchronization
|
mechanisms.
|
mechanisms.
|
|
|
|
|
|
|
|
|
HAL_TAS_TYPE
|
HAL_TAS_TYPE
|
|
|
|
|
The type for all test-and-set variables. The
|
The type for all test-and-set variables. The
|
test-and-set macros only support operations on
|
test-and-set macros only support operations on
|
a single bit (usually the least significant
|
a single bit (usually the least significant
|
bit) of this location. This allows for maximum
|
bit) of this location. This allows for maximum
|
flexibility in the implementation.
|
flexibility in the implementation.
|
|
|
|
|
|
|
|
|
|
|
HAL_TAS_SET( tas, oldb )
|
HAL_TAS_SET( tas, oldb )
|
|
|
|
|
Performs a test and set operation on the
|
Performs a test and set operation on the
|
location tas. oldb will contain true if
|
location tas. oldb will contain true if
|
the location was already set, and false if
|
the location was already set, and false if
|
it was clear.
|
it was clear.
|
|
|
|
|
|
|
|
|
|
|
HAL_TAS_CLEAR( tas, oldb )
|
HAL_TAS_CLEAR( tas, oldb )
|
|
|
|
|
Performs a test and clear operation on the
|
Performs a test and clear operation on the
|
location tas. oldb will contain true if
|
location tas. oldb will contain true if
|
the location was already set, and false if
|
the location was already set, and false if
|
it was clear.
|
it was clear.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Spinlocks
|
Spinlocks
|
|
|
|
|
Spinlocks provide inter-CPU locking. Normally they will be implemented
|
Spinlocks provide inter-CPU locking. Normally they will be implemented
|
on top of the test-and-set mechanism above, but may also be
|
on top of the test-and-set mechanism above, but may also be
|
implemented by other means if, for example, the hardware has more
|
implemented by other means if, for example, the hardware has more
|
direct support for spinlocks.
|
direct support for spinlocks.
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_TYPE
|
HAL_SPINLOCK_TYPE
|
|
|
|
|
The type for all spinlock variables.
|
The type for all spinlock variables.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_INIT_CLEAR
|
HAL_SPINLOCK_INIT_CLEAR
|
|
|
|
|
A value that may be assigned to a spinlock
|
A value that may be assigned to a spinlock
|
variable to initialize it to clear.
|
variable to initialize it to clear.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_INIT_SET
|
HAL_SPINLOCK_INIT_SET
|
|
|
|
|
A value that may be assigned to a spinlock
|
A value that may be assigned to a spinlock
|
variable to initialize it to set.
|
variable to initialize it to set.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_SPIN( lock )
|
HAL_SPINLOCK_SPIN( lock )
|
|
|
|
|
The caller spins in a busy loop waiting for
|
The caller spins in a busy loop waiting for
|
the lock to become clear. It then sets it and
|
the lock to become clear. It then sets it and
|
continues. This is all handled atomically, so
|
continues. This is all handled atomically, so
|
that there are no race conditions between CPUs.
|
that there are no race conditions between CPUs.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_CLEAR( lock )
|
HAL_SPINLOCK_CLEAR( lock )
|
|
|
|
|
The caller clears the lock. One of any waiting
|
The caller clears the lock. One of any waiting
|
spinners will then be able to proceed.
|
spinners will then be able to proceed.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_TRY( lock, val )
|
HAL_SPINLOCK_TRY( lock, val )
|
|
|
|
|
Attempts to set the lock. The value put in
|
Attempts to set the lock. The value put in
|
val will be true if the lock was
|
val will be true if the lock was
|
claimed successfully, and false if it was
|
claimed successfully, and false if it was
|
not.
|
not.
|
|
|
|
|
|
|
|
|
|
|
HAL_SPINLOCK_TEST( lock, val )
|
HAL_SPINLOCK_TEST( lock, val )
|
|
|
|
|
Tests the current value of the lock. The value
|
Tests the current value of the lock. The value
|
put in val will be true if the lock is
|
put in val will be true if the lock is
|
claimed and false of it is clear.
|
claimed and false of it is clear.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Scheduler Lock
|
Scheduler Lock
|
|
|
|
|
The scheduler lock is the main protection for all kernel data
|
The scheduler lock is the main protection for all kernel data
|
structures. By default the kernel implements the scheduler lock itself
|
structures. By default the kernel implements the scheduler lock itself
|
using a spinlock. However, if spinlocks cannot be supported by the
|
using a spinlock. However, if spinlocks cannot be supported by the
|
hardware, or there is a more efficient implementation available, the
|
hardware, or there is a more efficient implementation available, the
|
HAL may provide macros to implement the scheduler lock.
|
HAL may provide macros to implement the scheduler lock.
|
|
|
|
|
|
|
|
|
HAL_SMP_SCHEDLOCK_DATA_TYPE
|
HAL_SMP_SCHEDLOCK_DATA_TYPE
|
|
|
|
|
A data type, possibly a structure, that
|
A data type, possibly a structure, that
|
contains any data items needed by the
|
contains any data items needed by the
|
scheduler lock implementation. A variable of
|
scheduler lock implementation. A variable of
|
this type will be instantiated as a static
|
this type will be instantiated as a static
|
member of the Cyg_Scheduler_SchedLock class
|
member of the Cyg_Scheduler_SchedLock class
|
and passed to all the following macros.
|
and passed to all the following macros.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_SCHEDLOCK_INIT( lock, data )
|
HAL_SMP_SCHEDLOCK_INIT( lock, data )
|
|
|
|
|
Initialize the scheduler lock. The lock
|
Initialize the scheduler lock. The lock
|
argument is the scheduler lock counter and the
|
argument is the scheduler lock counter and the
|
data argument is a variable of
|
data argument is a variable of
|
HAL_SMP_SCHEDLOCK_DATA_TYPE type.
|
HAL_SMP_SCHEDLOCK_DATA_TYPE type.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_SCHEDLOCK_INC( lock, data )
|
HAL_SMP_SCHEDLOCK_INC( lock, data )
|
|
|
|
|
Increment the scheduler lock. The first
|
Increment the scheduler lock. The first
|
increment of the lock from zero to one for any
|
increment of the lock from zero to one for any
|
CPU may cause it to wait until the lock is
|
CPU may cause it to wait until the lock is
|
zeroed by another CPU. Subsequent increments
|
zeroed by another CPU. Subsequent increments
|
should be less expensive since this CPU
|
should be less expensive since this CPU
|
already holds the lock.
|
already holds the lock.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_SCHEDLOCK_ZERO( lock, data )
|
HAL_SMP_SCHEDLOCK_ZERO( lock, data )
|
|
|
|
|
Zero the scheduler lock. This operation will
|
Zero the scheduler lock. This operation will
|
also clear the lock so that other CPUs may
|
also clear the lock so that other CPUs may
|
claim it.
|
claim it.
|
|
|
|
|
|
|
|
|
|
|
HAL_SMP_SCHEDLOCK_SET( lock, data, new )
|
HAL_SMP_SCHEDLOCK_SET( lock, data, new )
|
|
|
|
|
Set the lock to a different value, in
|
Set the lock to a different value, in
|
new. This is only called when the lock is
|
new. This is only called when the lock is
|
already known to be owned by the current CPU. It is never called to
|
already known to be owned by the current CPU. It is never called to
|
zero the lock, or to increment it from zero.
|
zero the lock, or to increment it from zero.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Interrupt Routing
|
Interrupt Routing
|
|
|
|
|
The routing of interrupts to different CPUs is supported by two new
|
The routing of interrupts to different CPUs is supported by two new
|
interfaces in hal_intr.h.
|
interfaces in hal_intr.h.
|
|
|
|
|
|
|
Once an interrupt has been routed to a new CPU, the existing vector
|
Once an interrupt has been routed to a new CPU, the existing vector
|
masking and configuration operations should take account of the CPU
|
masking and configuration operations should take account of the CPU
|
routing. For example, if the operation is not invoked on the
|
routing. For example, if the operation is not invoked on the
|
destination CPU itself, then the HAL may need to arrange to transfer
|
destination CPU itself, then the HAL may need to arrange to transfer
|
the operation to the destination CPU for correct application.
|
the operation to the destination CPU for correct application.
|
|
|
|
|
|
|
|
|
HAL_INTERRUPT_SET_CPU( vector, cpu )
|
HAL_INTERRUPT_SET_CPU( vector, cpu )
|
|
|
|
|
Route the interrupt for the given vector to
|
Route the interrupt for the given vector to
|
the given cpu.
|
the given cpu.
|
|
|
|
|
|
|
|
|
|
|
HAL_INTERRUPT_GET_CPU( vector, cpu )
|
HAL_INTERRUPT_GET_CPU( vector, cpu )
|
|
|
|
|
Set cpu to the id of the CPU to which this
|
Set cpu to the id of the CPU to which this
|
vector is routed.
|
vector is routed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Exception Handling
|
Exception Handling
|
|
|
|
|
|
|
|
|
Most of the HAL consists of simple macros or functions that are
|
Most of the HAL consists of simple macros or functions that are
|
called via the interfaces described in the previous section. These
|
called via the interfaces described in the previous section. These
|
just perform whatever operation is required by accessing the hardware
|
just perform whatever operation is required by accessing the hardware
|
and then return. The exception to this is the handling of exceptions:
|
and then return. The exception to this is the handling of exceptions:
|
either synchronous hardware traps or asynchronous device
|
either synchronous hardware traps or asynchronous device
|
interrupts. Here control is passed first to the HAL, which then passed
|
interrupts. Here control is passed first to the HAL, which then passed
|
it on to eCos or the application. After eCos has finished with it,
|
it on to eCos or the application. After eCos has finished with it,
|
control is then passed back to the HAL for it to tidy up the CPU state
|
control is then passed back to the HAL for it to tidy up the CPU state
|
and resume processing from the point at which the exception occurred.
|
and resume processing from the point at which the exception occurred.
|
|
|
|
|
|
|
The HAL exceptions handling code is usually found in the file
|
The HAL exceptions handling code is usually found in the file
|
vectors.S in the architecture HAL. Since the
|
vectors.S in the architecture HAL. Since the
|
reset entry point is usually implemented as one of these it also deals
|
reset entry point is usually implemented as one of these it also deals
|
with system startup.
|
with system startup.
|
|
|
|
|
|
|
The exact implementation of this code is under the control of the HAL
|
The exact implementation of this code is under the control of the HAL
|
implementer. So long as it interacts correctly with the interfaces
|
implementer. So long as it interacts correctly with the interfaces
|
defined previously it may take any form. However, all current
|
defined previously it may take any form. However, all current
|
implementation follow the same pattern, and there should be a very
|
implementation follow the same pattern, and there should be a very
|
good reason to break with this. The rest of this section describes
|
good reason to break with this. The rest of this section describes
|
these operate.
|
these operate.
|
|
|
|
|
|
|
Exception handling normally deals with the following broad areas of
|
Exception handling normally deals with the following broad areas of
|
functionality:
|
functionality:
|
|
|
|
|
|
|
|
|
Startup and initialization.
|
Startup and initialization.
|
|
|
|
|
|
|
Hardware exception delivery.
|
Hardware exception delivery.
|
|
|
|
|
|
|
Default handling of synchronous exceptions.
|
Default handling of synchronous exceptions.
|
|
|
|
|
|
|
Default handling of asynchronous interrupts.
|
Default handling of asynchronous interrupts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HAL Startup
|
HAL Startup
|
|
|
|
|
Execution normally begins at the reset vector with
|
Execution normally begins at the reset vector with
|
the machine in a minimal startup state. From here the HAL needs to get
|
the machine in a minimal startup state. From here the HAL needs to get
|
the machine running, set up the execution environment for the
|
the machine running, set up the execution environment for the
|
application, and finally invoke its entry point.
|
application, and finally invoke its entry point.
|
|
|
|
|
|
|
The following is a list of the jobs that need to be done in
|
The following is a list of the jobs that need to be done in
|
approximately the order in which they should be accomplished. Many
|
approximately the order in which they should be accomplished. Many
|
of these will not be needed in some configurations.
|
of these will not be needed in some configurations.
|
|
|
|
|
|
|
|
|
|
|
Initialize the hardware. This may involve initializing several
|
Initialize the hardware. This may involve initializing several
|
subsystems in both the architecture, variant and platform
|
subsystems in both the architecture, variant and platform
|
HALs. These include:
|
HALs. These include:
|
|
|
|
|
|
|
|
|
Initialize various CPU status registers. Most importantly, the CPU
|
Initialize various CPU status registers. Most importantly, the CPU
|
interrupt mask should be set to disable interrupts.
|
interrupt mask should be set to disable interrupts.
|
|
|
|
|
|
|
|
|
|
|
Initialize the MMU, if it is used. On many platforms it is
|
Initialize the MMU, if it is used. On many platforms it is
|
only possible to control the cacheability of address ranges
|
only possible to control the cacheability of address ranges
|
via the MMU. Also, it may be necessary to remap RAM and device
|
via the MMU. Also, it may be necessary to remap RAM and device
|
registers to locations other than their defaults. However, for
|
registers to locations other than their defaults. However, for
|
simplicity, the mapping should be kept as close to one-to-one
|
simplicity, the mapping should be kept as close to one-to-one
|
physical-to-virtual as possible.
|
physical-to-virtual as possible.
|
|
|
|
|
|
|
|
|
|
|
Set up the memory controller to access RAM, ROM and I/O devices
|
Set up the memory controller to access RAM, ROM and I/O devices
|
correctly. Until this is done it may not be possible to access
|
correctly. Until this is done it may not be possible to access
|
RAM. If this is a ROMRAM startup then the program code can
|
RAM. If this is a ROMRAM startup then the program code can
|
now be copied to its RAM address and control transferred to it.
|
now be copied to its RAM address and control transferred to it.
|
|
|
|
|
|
|
|
|
|
|
Set up any bus bridges and support chips. Often access to
|
Set up any bus bridges and support chips. Often access to
|
device registers needs to go through various bus bridges and
|
device registers needs to go through various bus bridges and
|
other intermediary devices. In many systems these are combined
|
other intermediary devices. In many systems these are combined
|
with the memory controller, so it makes sense to set these up
|
with the memory controller, so it makes sense to set these up
|
together. This is particularly important if early diagnostic
|
together. This is particularly important if early diagnostic
|
output needs to go through one of these devices.
|
output needs to go through one of these devices.
|
|
|
|
|
|
|
|
|
|
|
Set up diagnostic mechanisms. If the platform includes an LED or
|
Set up diagnostic mechanisms. If the platform includes an LED or
|
LCD output device, it often makes sense to output progress
|
LCD output device, it often makes sense to output progress
|
indications on this during startup. This helps with diagnosing
|
indications on this during startup. This helps with diagnosing
|
hardware and software errors.
|
hardware and software errors.
|
|
|
|
|
|
|
|
|
|
|
Initialize floating point and other extensions such as SIMD
|
Initialize floating point and other extensions such as SIMD
|
and multimedia engines. It is usually necessary to enable
|
and multimedia engines. It is usually necessary to enable
|
these and maybe initialize control and exception registers for
|
these and maybe initialize control and exception registers for
|
these extensions.
|
these extensions.
|
|
|
|
|
|
|
|
|
|
|
|
|
Initialize interrupt controller. At the very least, it should
|
Initialize interrupt controller. At the very least, it should
|
be configured to mask all interrupts. It may also be necessary
|
be configured to mask all interrupts. It may also be necessary
|
to set up the mapping from the interrupt controller's vector
|
to set up the mapping from the interrupt controller's vector
|
number space to the CPU's exception number space. Similar
|
number space to the CPU's exception number space. Similar
|
mappings may need to be set up between primary and secondary
|
mappings may need to be set up between primary and secondary
|
interrupt controllers.
|
interrupt controllers.
|
|
|
|
|
|
|
|
|
|
|
Disable and initialize the caches. The caches should not
|
Disable and initialize the caches. The caches should not
|
normally be enabled at this point, but it may be necessary to
|
normally be enabled at this point, but it may be necessary to
|
clear or initialize them so that they can be enabled
|
clear or initialize them so that they can be enabled
|
later. Some architectures require that the caches be
|
later. Some architectures require that the caches be
|
explicitly reinitialized after a power-on reset.
|
explicitly reinitialized after a power-on reset.
|
|
|
|
|
|
|
|
|
|
|
|
|
Initialize the timer, clock etc. While the timer used for RTC
|
Initialize the timer, clock etc. While the timer used for RTC
|
interrupts will be initialized later, it may be necessary to
|
interrupts will be initialized later, it may be necessary to
|
set up the clocks that drive it here.
|
set up the clocks that drive it here.
|
|
|
|
|
|
|
|
|
|
|
The exact order in which these initializations is done is
|
The exact order in which these initializations is done is
|
architecture or variant specific. It is also often not necessary
|
architecture or variant specific. It is also often not necessary
|
to do anything at all for some of these options. These fragments
|
to do anything at all for some of these options. These fragments
|
of code should concentrate on getting the target up and running so
|
of code should concentrate on getting the target up and running so
|
that C function calls can be made and code can be run. More
|
that C function calls can be made and code can be run. More
|
complex initializations that cannot be done in assembly code may
|
complex initializations that cannot be done in assembly code may
|
be postponed until calls to
|
be postponed until calls to
|
hal_variant_init() or
|
hal_variant_init() or
|
hal_platform_init() are made.
|
hal_platform_init() are made.
|
|
|
|
|
|
|
Not all of these initializations need to be done for all startup
|
Not all of these initializations need to be done for all startup
|
types. In particular, RAM startups can reasonably assume that the
|
types. In particular, RAM startups can reasonably assume that the
|
ROM monitor or loader has already done most of this work.
|
ROM monitor or loader has already done most of this work.
|
|
|
|
|
|
|
|
|
|
|
|
|
Set up the stack pointer, this allows subsequent initialization
|
Set up the stack pointer, this allows subsequent initialization
|
code to make proper procedure calls. Usually the interrupt stack
|
code to make proper procedure calls. Usually the interrupt stack
|
is used for this purpose since it is available, large enough, and
|
is used for this purpose since it is available, large enough, and
|
will be reused for other purposes later.
|
will be reused for other purposes later.
|
|
|
|
|
|
|
|
|
|
|
Initialize any global pointer register needed for access to
|
Initialize any global pointer register needed for access to
|
globally defined variables. This allows subsequent initialization
|
globally defined variables. This allows subsequent initialization
|
code to access global variables.
|
code to access global variables.
|
|
|
|
|
|
|
|
|
|
|
If the system is starting from ROM, copy the ROM template of the
|
If the system is starting from ROM, copy the ROM template of the
|
.data section out to its correct position in
|
.data section out to its correct position in
|
RAM. ().
|
RAM. ().
|
|
|
|
|
|
|
|
|
|
|
Zero the .bss section.
|
Zero the .bss section.
|
|
|
|
|
|
|
|
|
|
|
Create a suitable C call stack frame. This may involve making
|
Create a suitable C call stack frame. This may involve making
|
stack space for call frames, and arguments, and initializing the
|
stack space for call frames, and arguments, and initializing the
|
back pointers to halt a GDB backtrace operation.
|
back pointers to halt a GDB backtrace operation.
|
|
|
|
|
|
|
|
|
|
|
Call hal_variant_init() and
|
Call hal_variant_init() and
|
hal_platform_init(). These will perform any
|
hal_platform_init(). These will perform any
|
additional initialization needed by the variant and platform. This
|
additional initialization needed by the variant and platform. This
|
typically includes further initialization of the interrupt
|
typically includes further initialization of the interrupt
|
controller, PCI bus bridges, basic IO devices and enabling the
|
controller, PCI bus bridges, basic IO devices and enabling the
|
caches.
|
caches.
|
|
|
|
|
|
|
|
|
|
|
Call cyg_hal_invoke_constructors() to run any
|
Call cyg_hal_invoke_constructors() to run any
|
static constructors.
|
static constructors.
|
|
|
|
|
|
|
|
|
|
|
Call cyg_start(). If
|
Call cyg_start(). If
|
cyg_start() returns, drop into an infinite
|
cyg_start() returns, drop into an infinite
|
loop.
|
loop.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vectors and VSRs
|
Vectors and VSRs
|
|
|
|
|
The CPU delivers all exceptions, whether
|
The CPU delivers all exceptions, whether
|
synchronous faults or asynchronous interrupts, to a set of hardware
|
synchronous faults or asynchronous interrupts, to a set of hardware
|
defined vectors. Depending on the architecture, these may be
|
defined vectors. Depending on the architecture, these may be
|
implemented in a number of different ways. Examples of existing
|
implemented in a number of different ways. Examples of existing
|
mechanisms are:
|
mechanisms are:
|
|
|
|
|
|
|
|
|
PowerPC
|
PowerPC
|
|
|
|
|
Exceptions are vectored to locations 256 bytes apart starting at
|
Exceptions are vectored to locations 256 bytes apart starting at
|
either zero or 0xFFF00000. There are 16 such
|
either zero or 0xFFF00000. There are 16 such
|
vectors defined by the basic architecture and extra vectors may
|
vectors defined by the basic architecture and extra vectors may
|
be defined by specific variants. One of the base vectors is for
|
be defined by specific variants. One of the base vectors is for
|
all external interrupts, and another is for the architecture
|
all external interrupts, and another is for the architecture
|
defined timer.
|
defined timer.
|
|
|
|
|
|
|
|
|
|
|
MIPS
|
MIPS
|
|
|
|
|
Most exceptions and all interrupts are vectored to a single
|
Most exceptions and all interrupts are vectored to a single
|
address at either 0x80000000 or
|
address at either 0x80000000 or
|
0xBFC00180. Software is responsible for
|
0xBFC00180. Software is responsible for
|
reading the exception code from the CPU cause
|
reading the exception code from the CPU cause
|
register to discover its true source. Some TLB and debug
|
register to discover its true source. Some TLB and debug
|
exceptions are delivered to different vector addresses, but
|
exceptions are delivered to different vector addresses, but
|
these are not used currently by eCos. One of the exception codes
|
these are not used currently by eCos. One of the exception codes
|
in the cause register indicates an external
|
in the cause register indicates an external
|
interrupt. Additional bits in the cause
|
interrupt. Additional bits in the cause
|
register provide a first-level decode for the interrupt source,
|
register provide a first-level decode for the interrupt source,
|
one of which represents an architecture defined timer.
|
one of which represents an architecture defined timer.
|
|
|
|
|
|
|
|
|
|
|
IA32
|
IA32
|
|
|
|
|
Exceptions are delivered via an Interrupt Descriptor Table (IDT)
|
Exceptions are delivered via an Interrupt Descriptor Table (IDT)
|
which is essentially an indirection table indexed by exception
|
which is essentially an indirection table indexed by exception
|
number. The IDT may be placed anywhere in memory. In PC hardware
|
number. The IDT may be placed anywhere in memory. In PC hardware
|
the standard interrupt controller can be programmed to deliver
|
the standard interrupt controller can be programmed to deliver
|
the external interrupts to a block of 16 vectors at any offset
|
the external interrupts to a block of 16 vectors at any offset
|
in the IDT. There is no hardware supplied mechanism for
|
in the IDT. There is no hardware supplied mechanism for
|
determining the vector taken, other than from the address jumped
|
determining the vector taken, other than from the address jumped
|
to.
|
to.
|
|
|
|
|
|
|
|
|
|
|
ARM
|
ARM
|
|
|
|
|
All exceptions, including the FIQ and IRQ interrupts, are
|
All exceptions, including the FIQ and IRQ interrupts, are
|
vectored to locations four bytes apart starting at zero. There
|
vectored to locations four bytes apart starting at zero. There
|
is only room for one instruction here, which must immediately
|
is only room for one instruction here, which must immediately
|
jump out to handling code higher in memory. Interrupt sources
|
jump out to handling code higher in memory. Interrupt sources
|
have to be decoded entirely from the interrupt controller.
|
have to be decoded entirely from the interrupt controller.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
With such a wide variety of hardware approaches, it is not possible to
|
With such a wide variety of hardware approaches, it is not possible to
|
provide a generic mechanism for the substitution of exception vectors
|
provide a generic mechanism for the substitution of exception vectors
|
directly. Therefore, eCos translates all of these mechanisms in to a
|
directly. Therefore, eCos translates all of these mechanisms in to a
|
common approach that can be used by portable code on all platforms.
|
common approach that can be used by portable code on all platforms.
|
|
|
|
|
|
|
The mechanism implemented is to attach to each hardware vector a short
|
The mechanism implemented is to attach to each hardware vector a short
|
piece of trampoline code that makes an indirect jump via a table to
|
piece of trampoline code that makes an indirect jump via a table to
|
the actual handler for the exception. This handler is called the
|
the actual handler for the exception. This handler is called the
|
Vector Service Routine (VSR) and the table is called the VSR table.
|
Vector Service Routine (VSR) and the table is called the VSR table.
|
|
|
|
|
|
|
The trampoline code performs the absolute minimum processing necessary
|
The trampoline code performs the absolute minimum processing necessary
|
to identify the exception source, and jump to the VSR. The VSR is then
|
to identify the exception source, and jump to the VSR. The VSR is then
|
responsible for saving the CPU state and taking the necessary actions
|
responsible for saving the CPU state and taking the necessary actions
|
to handle the exception or interrupt. The entry conditions for the VSR
|
to handle the exception or interrupt. The entry conditions for the VSR
|
are as close to the raw hardware exception entry state as possible -
|
are as close to the raw hardware exception entry state as possible -
|
although on some platforms the trampoline will have had to move or
|
although on some platforms the trampoline will have had to move or
|
reorganize some registers to do its job.
|
reorganize some registers to do its job.
|
|
|
|
|
|
|
To make this more concrete, consider how the trampoline code operates
|
To make this more concrete, consider how the trampoline code operates
|
in each of the architectures described above:
|
in each of the architectures described above:
|
|
|
|
|
|
|
|
|
|
|
PowerPC
|
PowerPC
|
|
|
|
|
A separate trampoline is contained in each of the vector
|
A separate trampoline is contained in each of the vector
|
locations. This code saves a few work registers away to the
|
locations. This code saves a few work registers away to the
|
special purposes registers available, loads the exception number
|
special purposes registers available, loads the exception number
|
into a register and then uses that to index the VSR table and
|
into a register and then uses that to index the VSR table and
|
jump to the VSR. The VSR is entered with some registers move to
|
jump to the VSR. The VSR is entered with some registers move to
|
the SPRs, and one of the data register containing the number of
|
the SPRs, and one of the data register containing the number of
|
the vector taken.
|
the vector taken.
|
|
|
|
|
|
|
|
|
|
|
MIPS
|
MIPS
|
|
|
|
|
A single trampoline routine attached to the common vector reads
|
A single trampoline routine attached to the common vector reads
|
the exception code out of the cause register
|
the exception code out of the cause register
|
and uses that value to index the VSR table and jump to the VSR.
|
and uses that value to index the VSR table and jump to the VSR.
|
The trampoline uses the two registers defined in the ABI for
|
The trampoline uses the two registers defined in the ABI for
|
kernel use to do this, one of these will contain the exception
|
kernel use to do this, one of these will contain the exception
|
vector number for the VSR.
|
vector number for the VSR.
|
|
|
|
|
|
|
|
|
|
|
IA32
|
IA32
|
|
|
|
|
There is a separate 3 or 4 instruction trampoline pointed to by
|
There is a separate 3 or 4 instruction trampoline pointed to by
|
each active IDT table entry. The trampoline for exceptions that
|
each active IDT table entry. The trampoline for exceptions that
|
also have an error code pop it from the stack and put it into a
|
also have an error code pop it from the stack and put it into a
|
memory location. Trampolines for non-error-code exceptions just
|
memory location. Trampolines for non-error-code exceptions just
|
zero the memory location. Then all trampolines push an
|
zero the memory location. Then all trampolines push an
|
interrupt/exception number onto the stack, and take an indirect
|
interrupt/exception number onto the stack, and take an indirect
|
jump through a precalculated offset in the VSR table. This is
|
jump through a precalculated offset in the VSR table. This is
|
all done without saving any registers, using memory-only
|
all done without saving any registers, using memory-only
|
operations. The VSR is entered with the vector number pushed
|
operations. The VSR is entered with the vector number pushed
|
onto the stack on top of the standard hardware saved state.
|
onto the stack on top of the standard hardware saved state.
|
|
|
|
|
|
|
|
|
|
|
ARM
|
ARM
|
|
|
|
|
The trampoline consists solely of the single instruction at the
|
The trampoline consists solely of the single instruction at the
|
exception entry point. This is an indirect jump via a location
|
exception entry point. This is an indirect jump via a location
|
32 bytes higher in memory. These locations, from
|
32 bytes higher in memory. These locations, from
|
0x20 up, form the VSR table. Since each VSR
|
0x20 up, form the VSR table. Since each VSR
|
is entered in a different CPU mode
|
is entered in a different CPU mode
|
(SVC,UNDEF,ABORT,IRQ or FIQ) there has to be a
|
(SVC,UNDEF,ABORT,IRQ or FIQ) there has to be a
|
different VSR for each exception that knows how to save the CPU
|
different VSR for each exception that knows how to save the CPU
|
state correctly.
|
state correctly.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Default Synchronous Exception Handling
|
Default Synchronous Exception Handling
|
|
|
|
|
Most synchronous exception VSR table entries will point to a default
|
Most synchronous exception VSR table entries will point to a default
|
exception VSR which is responsible for handling all exceptions in a
|
exception VSR which is responsible for handling all exceptions in a
|
generic manner. The default VSR simply saves the CPU state, makes any
|
generic manner. The default VSR simply saves the CPU state, makes any
|
adjustments to the CPU state that is necessary, and calls
|
adjustments to the CPU state that is necessary, and calls
|
cyg_hal_exception_handler().
|
cyg_hal_exception_handler().
|
|
|
|
|
|
|
cyg_hal_exception_handler() needs to pass the
|
cyg_hal_exception_handler() needs to pass the
|
exception on to some handling code. There are two basic destinations:
|
exception on to some handling code. There are two basic destinations:
|
enter GDB or pass the exception up to eCos. Exactly which
|
enter GDB or pass the exception up to eCos. Exactly which
|
destination is taken depends on the configuration. When the GDB stubs are
|
destination is taken depends on the configuration. When the GDB stubs are
|
included then the exception is passed to them, otherwise it is passed
|
included then the exception is passed to them, otherwise it is passed
|
to eCos.
|
to eCos.
|
|
|
|
|
|
|
If an eCos application has been loaded by RedBoot then the VSR table
|
If an eCos application has been loaded by RedBoot then the VSR table
|
entries will all point into RedBoot's exception VSR, and will
|
entries will all point into RedBoot's exception VSR, and will
|
therefore enter GDB if an exception occurs. If the eCos application
|
therefore enter GDB if an exception occurs. If the eCos application
|
wants to handle an exception itself, it needs to replace the the VSR
|
wants to handle an exception itself, it needs to replace the the VSR
|
table entry with one pointing to its own VSR. It can do this with the
|
table entry with one pointing to its own VSR. It can do this with the
|
HAL_VSR_SET_TO_ECOS_HANDLER() macro.
|
HAL_VSR_SET_TO_ECOS_HANDLER() macro.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Default Interrupt Handling
|
Default Interrupt Handling
|
|
|
|
|
Most asynchronous external interrupt vectors will point to a default
|
Most asynchronous external interrupt vectors will point to a default
|
interrupt VSR which decodes the actual interrupt being delivered from
|
interrupt VSR which decodes the actual interrupt being delivered from
|
the interrupt controller and invokes the appropriate ISR.
|
the interrupt controller and invokes the appropriate ISR.
|
|
|
|
|
|
|
The default interrupt VSR has a number of responsibilities if it is
|
The default interrupt VSR has a number of responsibilities if it is
|
going to interact with the Kernel cleanly and allow interrupts to
|
going to interact with the Kernel cleanly and allow interrupts to
|
cause thread preemption.
|
cause thread preemption.
|
|
|
|
|
|
|
To support this VSR an ISR vector table is needed. For each valid
|
To support this VSR an ISR vector table is needed. For each valid
|
vector three pointers need to be stored: the ISR, its data pointer and
|
vector three pointers need to be stored: the ISR, its data pointer and
|
an opaque (to the HAL) interrupt object pointer needed by the
|
an opaque (to the HAL) interrupt object pointer needed by the
|
kernel. It is implementation defined whether these are stored in a
|
kernel. It is implementation defined whether these are stored in a
|
single table of triples, or in three separate tables.
|
single table of triples, or in three separate tables.
|
|
|
|
|
|
|
The VSR follows the following approximate plan:
|
The VSR follows the following approximate plan:
|
|
|
|
|
|
|
|
|
|
|
Save the CPU state. In non-debug configurations, it may be
|
Save the CPU state. In non-debug configurations, it may be
|
possible to get away with saving less than the entire machine
|
possible to get away with saving less than the entire machine
|
state. The option
|
state. The option
|
CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
|
CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
|
is supported in some targets to do this.
|
is supported in some targets to do this.
|
|
|
|
|
|
|
|
|
|
|
Increment the kernel scheduler lock. This is a static member of
|
Increment the kernel scheduler lock. This is a static member of
|
the Cyg_Scheduler class, however it has also been aliased to
|
the Cyg_Scheduler class, however it has also been aliased to
|
cyg_scheduler_sched_lock so that it can be
|
cyg_scheduler_sched_lock so that it can be
|
accessed from assembly code.
|
accessed from assembly code.
|
|
|
|
|
|
|
|
|
|
|
(Optional) Switch to an interrupt stack if not already running on
|
(Optional) Switch to an interrupt stack if not already running on
|
it. This allows nested interrupts to be delivered without needing
|
it. This allows nested interrupts to be delivered without needing
|
every thread to have a stack large enough to take the maximum
|
every thread to have a stack large enough to take the maximum
|
possible nesting. It is implementation defined how to detect
|
possible nesting. It is implementation defined how to detect
|
whether this is a nested interrupt but there are two basic
|
whether this is a nested interrupt but there are two basic
|
techniques. The first is to inspect the stack pointer and switch
|
techniques. The first is to inspect the stack pointer and switch
|
only if it is not currently within the interrupt stack range; the
|
only if it is not currently within the interrupt stack range; the
|
second is to maintain a counter of the interrupt nesting level and
|
second is to maintain a counter of the interrupt nesting level and
|
switch only if it is zero. The option
|
switch only if it is zero. The option
|
CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
|
CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
|
controls whether this happens.
|
controls whether this happens.
|
|
|
|
|
|
|
|
|
|
|
Decode the actual external interrupt being delivered from
|
Decode the actual external interrupt being delivered from
|
the interrupt controller. This will yield the ISR vector
|
the interrupt controller. This will yield the ISR vector
|
number. The code to do this usually needs to come from the
|
number. The code to do this usually needs to come from the
|
variant or platform HAL, so is usually present in the form of a
|
variant or platform HAL, so is usually present in the form of a
|
macro or procedure callout.
|
macro or procedure callout.
|
|
|
|
|
|
|
|
|
|
|
(Optional) Re-enable interrupts to permit nesting. At this point
|
(Optional) Re-enable interrupts to permit nesting. At this point
|
we can potentially allow higher priority interrupts to occur. It
|
we can potentially allow higher priority interrupts to occur. It
|
depends on the interrupt architecture of the CPU and platform
|
depends on the interrupt architecture of the CPU and platform
|
whether more interrupts will occur at this point, or whether they
|
whether more interrupts will occur at this point, or whether they
|
will only be delivered after the current interrupt has been
|
will only be delivered after the current interrupt has been
|
acknowledged (by a call to
|
acknowledged (by a call to
|
HAL_INTERRUPT_ACKNOWLEDGE() in the ISR).
|
HAL_INTERRUPT_ACKNOWLEDGE() in the ISR).
|
|
|
|
|
|
|
|
|
|
|
Using the ISR vector number as an index, retrieve the
|
Using the ISR vector number as an index, retrieve the
|
ISR pointer and its data pointer from the ISR vector table.
|
ISR pointer and its data pointer from the ISR vector table.
|
|
|
|
|
|
|
|
|
|
|
Construct a C call stack frame. This may involve making stack
|
Construct a C call stack frame. This may involve making stack
|
space for call frames, and arguments, and initializing the back
|
space for call frames, and arguments, and initializing the back
|
pointers to halt a GDB backtrace operation.
|
pointers to halt a GDB backtrace operation.
|
|
|
|
|
|
|
|
|
|
|
Call the ISR, passing the vector number and data pointer. The
|
Call the ISR, passing the vector number and data pointer. The
|
vector number and a pointer to the saved state should be preserved
|
vector number and a pointer to the saved state should be preserved
|
across this call, preferably by storing them in registers that are
|
across this call, preferably by storing them in registers that are
|
defined to be callee-saved by the calling conventions.
|
defined to be callee-saved by the calling conventions.
|
|
|
|
|
|
|
|
|
|
|
If this is an un-nested interrupt and a separate interrupt
|
If this is an un-nested interrupt and a separate interrupt
|
stack is being used, switch back to the interrupted thread's
|
stack is being used, switch back to the interrupted thread's
|
own stack.
|
own stack.
|
|
|
|
|
|
|
|
|
|
|
Use the saved ISR vector number to get the interrupt object
|
Use the saved ISR vector number to get the interrupt object
|
pointer from the ISR vector table.
|
pointer from the ISR vector table.
|
|
|
|
|
|
|
|
|
|
|
Call interrupt_end() passing it the return
|
Call interrupt_end() passing it the return
|
value from the ISR, the interrupt object pointer and a pointer to
|
value from the ISR, the interrupt object pointer and a pointer to
|
the saved CPU state. This function is implemented by the Kernel
|
the saved CPU state. This function is implemented by the Kernel
|
and is responsible for finishing off the interrupt
|
and is responsible for finishing off the interrupt
|
handling. Specifically, it may post a DSR depending on the ISR
|
handling. Specifically, it may post a DSR depending on the ISR
|
return value, and will decrement the scheduler lock. If the lock
|
return value, and will decrement the scheduler lock. If the lock
|
is zeroed by this operation then any posted DSRs may be called and
|
is zeroed by this operation then any posted DSRs may be called and
|
may in turn result in a thread context switch.
|
may in turn result in a thread context switch.
|
|
|
|
|
|
|
|
|
|
|
The return from interrupt_end() may occur
|
The return from interrupt_end() may occur
|
some time after the call. Many other threads may have executed in
|
some time after the call. Many other threads may have executed in
|
the meantime. So here all we may do is restore the machine state
|
the meantime. So here all we may do is restore the machine state
|
and resume execution of the interrupted thread. Depending on the
|
and resume execution of the interrupted thread. Depending on the
|
architecture, it may be necessary to disable interrupts again for
|
architecture, it may be necessary to disable interrupts again for
|
part of this.
|
part of this.
|
|
|
|
|
|
|
|
|
|
|
|
|
The detailed order of these steps may vary slightly depending on the
|
The detailed order of these steps may vary slightly depending on the
|
architecture, in particular where interrupts are enabled and disabled.
|
architecture, in particular where interrupts are enabled and disabled.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
&hal-common-porting-sgml;
|
&hal-common-porting-sgml;
|
|
|
|
|
|
|
|
|
|
|
Future developments
|
Future developments
|
|
|
|
|
The HAL is not complete, and will evolve and increase over
|
The HAL is not complete, and will evolve and increase over
|
time. Among the intended developments are:
|
time. Among the intended developments are:
|
|
|
|
|
|
|
Common macros for interpreting the contents of a saved
|
Common macros for interpreting the contents of a saved
|
machine context. These would allow portable code, such as debug
|
machine context. These would allow portable code, such as debug
|
stubs, to extract such values as the program counter and stack pointer
|
stubs, to extract such values as the program counter and stack pointer
|
from a state without having to interpret a HAL_SavedRegisters structure
|
from a state without having to interpret a HAL_SavedRegisters structure
|
directly.
|
directly.
|
|
|
|
|
Debugging support. Macros to set and clear hardware and
|
Debugging support. Macros to set and clear hardware and
|
software breakpoints. Access to other areas of machine state may
|
software breakpoints. Access to other areas of machine state may
|
also be supported.
|
also be supported.
|
|
|
|
|
Static initialization support. The current HAL provides a
|
Static initialization support. The current HAL provides a
|
dynamic interface to things like thread context initialization and ISR
|
dynamic interface to things like thread context initialization and ISR
|
attachment. We also need to be able to define the system entirely
|
attachment. We also need to be able to define the system entirely
|
statically so that it is ready to go on restart, without needing to
|
statically so that it is ready to go on restart, without needing to
|
run code. This will require extra macros to define these
|
run code. This will require extra macros to define these
|
initializations. Such support may have a consequential effect on the
|
initializations. Such support may have a consequential effect on the
|
current HAL specification.
|
current HAL specification.
|
|
|
|
|
CPU state control. Many CPUs have both kernel and user
|
CPU state control. Many CPUs have both kernel and user
|
states. Although it is not intended to run any code in user state
|
states. Although it is not intended to run any code in user state
|
for the foreseeable future, it is possible that this may happen
|
for the foreseeable future, it is possible that this may happen
|
eventually. If this is the case, then some minor changes may be needed
|
eventually. If this is the case, then some minor changes may be needed
|
to the current HAL API to accommodate this. These should mostly
|
to the current HAL API to accommodate this. These should mostly
|
be extensions, but minor changes in semantics may also be required.
|
be extensions, but minor changes in semantics may also be required.
|
|
|
|
|
Physical memory management. Many embedded systems have
|
Physical memory management. Many embedded systems have
|
multiple memory areas with varying properties such as base address,
|
multiple memory areas with varying properties such as base address,
|
size, speed, bus width, cacheability and persistence. An API is
|
size, speed, bus width, cacheability and persistence. An API is
|
needed to support the discovery of this information about the machine's
|
needed to support the discovery of this information about the machine's
|
physical memory map.
|
physical memory map.
|
|
|
|
|
Memory management control. Some embedded processors have
|
Memory management control. Some embedded processors have
|
a memory management unit. In some cases this must be enabled to
|
a memory management unit. In some cases this must be enabled to
|
allow the cache to be controlled, particularly if different regions
|
allow the cache to be controlled, particularly if different regions
|
of memory must have different caching properties. For some purposes,
|
of memory must have different caching properties. For some purposes,
|
in some systems, it will be useful to manipulate the MMU settings
|
in some systems, it will be useful to manipulate the MMU settings
|
dynamically.
|
dynamically.
|
|
|
|
|
Power management. Macros to access and control any power
|
Power management. Macros to access and control any power
|
management mechanisms available on the CPU implementation. These
|
management mechanisms available on the CPU implementation. These
|
would provide a substrate for a more general power management system
|
would provide a substrate for a more general power management system
|
that also involved device drivers and other hardware components.
|
that also involved device drivers and other hardware components.
|
|
|
|
|
Generic serial line macros. Most serial line devices operate
|
Generic serial line macros. Most serial line devices operate
|
in the same way, the only real differences being exactly which bits
|
in the same way, the only real differences being exactly which bits
|
in which registers perform the standard functions. It should be
|
in which registers perform the standard functions. It should be
|
possible to develop a set of HAL macros that provide basic serial
|
possible to develop a set of HAL macros that provide basic serial
|
line services such as baud rate setting, enabling interrupts, polling
|
line services such as baud rate setting, enabling interrupts, polling
|
for transmit or receive ready, transmitting and receiving data etc.
|
for transmit or receive ready, transmitting and receiving data etc.
|
Given these it should be possible to create a generic serial line
|
Given these it should be possible to create a generic serial line
|
device driver that will allow rapid bootstrapping on any new platform.
|
device driver that will allow rapid bootstrapping on any new platform.
|
It may be possible to extend this mechanism to other device types.
|
It may be possible to extend this mechanism to other device types.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|