OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [doc/] [html/] [ref/] [hal-porting-architecture.html] - Rev 581

Go to most recent revision | Compare with Previous | Blame | View Log

<!-- Copyright (C) 2003 Red Hat, Inc.                                -->
<!-- This material may be distributed only subject to the terms      -->
<!-- and conditions set forth in the Open Publication License, v1.0  -->
<!-- or later (the latest version is presently available at          -->
<!-- http://www.opencontent.org/openpub/).                           -->
<!-- Distribution of the work or derivative of the work in any       -->
<!-- standard (paper) book form is prohibited unless prior           -->
<!-- permission is obtained from the copyright holder.               -->
<HTML
><HEAD
><TITLE
>Architecture HAL Porting</TITLE
><meta name="MSSmartTagsPreventParsing" content="TRUE">
<META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+
"><LINK
REL="HOME"
TITLE="eCos Reference Manual"
HREF="ecos-ref.html"><LINK
REL="UP"
TITLE="	Porting Guide"
HREF="hal-porting-guide.html"><LINK
REL="PREVIOUS"
TITLE="Variant HAL Porting"
HREF="hal-porting-variant.html"><LINK
REL="NEXT"
TITLE="Future developments"
HREF="hal-future-developments.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>eCos Reference Manual</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="hal-porting-variant.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 11. Porting Guide</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="hal-future-developments.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="HAL-PORTING-ARCHITECTURE">Architecture HAL Porting</H1
><P
>A new architecture HAL is the most complex HAL to write, and it the
least easily described. Hence this section is presently nothing more
than a place holder for the future.</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN9793">HAL Architecture Porting Process</H2
><P
>The easiest way to make a new architecture HAL is simply to copy an
existing architecture HAL of an, if possible, closely matching
architecture and change all the files to match the new
architecture. The MIPS architecture HAL should be used if possible, as
it has the appropriate layout and coding conventions. Other HALs
may deviate from that norm in various ways.</P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Note: </B
> eCos is written for GCC. It requires C and C++
compiler support as well as a few compiler features introduced during
eCos development - so compilers older than eCos may not provide these
features. Note that there is no C++ support for any 8 or 16 bit
CPUs. Before you can undertake an eCos port, you need the required
compiler support.</P
></BLOCKQUOTE
></DIV
><P
>The following gives a rough outline of the steps needed to create a
new architecture HAL. The exact order and set of steps needed will
vary greatly from architecture to architecture, so a lot of
flexibility is required. And of course, if the architecture HAL is to
be tested, it is necessary to do variant and  platform ports for the
initial target simultaneously.</P
><P
></P
><OL
TYPE="1"
><LI
><P
>Make a new directory for the new architecture under the
<TT
CLASS="FILENAME"
>hal</TT
> directory in the source repository. Make an
<TT
CLASS="FILENAME"
>arch</TT
> directory under this and populate this with
the standard set of package directories.</P
></LI
><LI
><P
>Copy the CDL file from an example HAL changing its name to match the
new HAL. Edit the file, changing option names as appropriate. Delete
any options that are specific to the original HAL, and and any new
options that are necessary for the new architecture. This is likely to
be a continuing process during the development of the HAL. See <A
HREF="hal-porting-architecture.html#HAL-PORTING-ARCHITECTURE-CDL"
>the Section called <I
>CDL Requirements</I
></A
> for more details.</P
></LI
><LI
><P
>Copy the <TT
CLASS="FILENAME"
>hal_arch.h</TT
> file from an example
HAL. Within this file you need to change or define the following:</P
><P
></P
><UL
><LI
><P
>Define the <SPAN
CLASS="STRUCTNAME"
>HAL_SavedRegisters</SPAN
> structure. This
may need to reflect the save order of any group register save/restore
instructions, the interrupt and exception save and restore formats,
and the procedure calling conventions. It may also need to cater for
optional FPUs and other functional units. It can be quite difficult to
develop a layout that copes with all requirements.</P
></LI
><LI
><P
>Define the bit manipulation routines,
<TT
CLASS="LITERAL"
>HAL_LSBIT_INDEX()</TT
> and
<TT
CLASS="LITERAL"
>HAL_MSBIT_INDEX()</TT
>. If the architecture contains
instructions to perform these, or related, operations, then these
should be defined as inline assembler fragments. Otherwise make them
calls to functions.</P
></LI
><LI
><P
>Define <TT
CLASS="LITERAL"
>HAL_THREAD_INIT_CONTEXT()</TT
>. This initializes
a restorable CPU context onto a stack pointer so that a later call to
<TT
CLASS="LITERAL"
>HAL_THREAD_LOAD_CONTEXT()</TT
> or
<TT
CLASS="LITERAL"
>HAL_THREAD_SWITCH_CONTEXT()</TT
> will execute it
correctly. This macro needs to take account of the same optional
features of the architecture as the definition of
<SPAN
CLASS="STRUCTNAME"
>HAL_SavedRegisters</SPAN
>.</P
></LI
><LI
><P
>Define <TT
CLASS="LITERAL"
>HAL_THREAD_LOAD_CONTEXT()</TT
> and
<TT
CLASS="LITERAL"
>HAL_THREAD_SWITCH_CONTEXT()</TT
>. These should just be
calls to functions in <TT
CLASS="FILENAME"
>context.S</TT
>.</P
></LI
><LI
><P
>Define <TT
CLASS="LITERAL"
>HAL_REORDER_BARRIER()</TT
>. This prevents code
being moved by the compiler and is necessary in some order-sensitive
code. This macro is actually defined identically in all architecture,
so it can just be copied.</P
></LI
><LI
><P
>Define breakpoint support. The macro
<TT
CLASS="LITERAL"
>HAL_BREAKPOINT(label)</TT
> needs to be an inline assembly
fragment that invokes a breakpoint. The breakpoint instruction should
be labeled with the <TT
CLASS="PARAMETER"
><I
>label</I
></TT
>
argument. <TT
CLASS="LITERAL"
>HAL_BREAKINST</TT
> and
<TT
CLASS="LITERAL"
>HAL_BREAKINST_SIZE</TT
> define the breakpoint
instruction for debugging purposes.</P
></LI
><LI
><P
>Define GDB support. GDB views the registers of the target as a linear
array, with each register having a well defined offset. This array may
differ from the ordering defined in
<SPAN
CLASS="STRUCTNAME"
>HAL_SavedRegisters</SPAN
>. The macros
<TT
CLASS="LITERAL"
>HAL_GET_GDB_REGISTERS()</TT
> and
<TT
CLASS="LITERAL"
>HAL_SET_GDB_REGISTERS()</TT
> translate between the GDB
array and the <SPAN
CLASS="STRUCTNAME"
>HAL_SavedRegisters</SPAN
> structure.
The <TT
CLASS="LITERAL"
>HAL_THREAD_GET_SAVED_REGISTERS()</TT
> translates a
stack pointer saved by the context switch macros into a pointer to a
<SPAN
CLASS="STRUCTNAME"
>HAL_SavedRegisters</SPAN
> structure. Usually this is
a one-to-one translation, but this macro allows it to differ if
necessary.</P
></LI
><LI
><P
>Define long jump support. The type <SPAN
CLASS="TYPE"
>hal_jmp_buf</SPAN
> and the
functions <TT
CLASS="FUNCTION"
>hal_setjmp()</TT
> and
<TT
CLASS="LITERAL"
>hal_longjmp()</TT
> provide the underlying implementation
of the C library <TT
CLASS="FUNCTION"
>setjmp()</TT
> and
<TT
CLASS="FUNCTION"
>longjmp()</TT
>.</P
></LI
><LI
><P
>Define idle thread action. Generally the macro
<TT
CLASS="LITERAL"
>HAL_IDLE_THREAD_ACTION()</TT
> is defined to call a
function in <TT
CLASS="FILENAME"
>hal_misc.c</TT
>.</P
></LI
><LI
><P
>Define stack sizes. The macros
<TT
CLASS="LITERAL"
>CYGNUM_HAL_STACK_SIZE_MINIMUM</TT
> and
<TT
CLASS="LITERAL"
>CYGNUM_HAL_STACK_SIZE_TYPICAL</TT
> should be defined to
the minimum size for any thread stack and a reasonable default for
most threads respectively. It is usually best to construct these out
of component sizes for the CPU save state and procedure call stack
usage. These definitions should not use anything other than numerical
values since they can be used from assembly code in some HALs.</P
></LI
><LI
><P
>Define memory access macros. These macros provide translation between
cached and uncached and physical memory spaces. They usually consist
of masking out bits of the supplied address and ORing in alternative
address bits.</P
></LI
><LI
><P
>Define global pointer save/restore macros. These really only need
defining if the calling conventions of the architecture require a
global pointer (as does the MIPS architecture), they may be empty
otherwise. If it is necessary to define these, then take a look at the
MIPS implementation for an example.</P
></LI
></UL
></LI
><LI
><P
>Copy <TT
CLASS="FILENAME"
>hal_intr.h</TT
> from an example HAL. Within this
file you should change or define the following:</P
><P
></P
><UL
><LI
><P
>Define the exception vectors. These should be detailed in the
architecture specification. Essentially for each exception entry point
defined by the architecture there should be an entry in the VSR
table. The offsets of these VSR table entries should be defined here
by <TT
CLASS="LITERAL"
>CYGNUM_HAL_VECTOR_*</TT
> definitions. The size of the
VSR table also needs to be defined here.</P
></LI
><LI
><P
>Map any hardware exceptions to standard names. There is a group of
exception vector name of the form
<TT
CLASS="LITERAL"
>CYGNUM_HAL_EXCEPTION_*</TT
> that define a wide variety
of possible exceptions that many architectures raise. Generic code
detects whether the architecture can raise a given exception by
testing whether a given <TT
CLASS="LITERAL"
>CYGNUM_HAL_EXCEPTION_*</TT
>
definition is present. If it is present then its value is the vector
that raises that exception. This does not need to be a one-to-one
correspondence, and several <TT
CLASS="LITERAL"
>CYGNUM_HAL_EXCEPTION_*</TT
>
definitions may have the same value.</P
><P
>Interrupt vectors are usually defined in the variant or platform
HALs. The interrupt number space may either be continuous with the VSR
number space, where they share a vector table (as in the i386) or may
be a separate space where a separate decode stage is used (as in MIPS
or PowerPC).</P
></LI
><LI
><P
>Declare any static data used by the HAL to handle interrupts and
exceptions. This is usually three vectors for interrupts:
<TT
CLASS="LITERAL"
>hal_interrupt_handlers[]</TT
>,
<TT
CLASS="LITERAL"
>hal_interrupt_data[]</TT
> and
<TT
CLASS="LITERAL"
>hal_interrupt_objects[]</TT
>, which are sized according
to the interrupt vector definitions. In addition a definition for the
VSR table, <TT
CLASS="LITERAL"
>hal_vsr_table[]</TT
> should be made. These
vectors are normally defined in either <TT
CLASS="FILENAME"
>vectors.S</TT
>
or <TT
CLASS="FILENAME"
>hal_misc.c</TT
>.</P
></LI
><LI
><P
>Define interrupt enable/disable macros. These are normally inline
assembly fragments to execute the instructions, or manipulate the CPU
register, that contains the CPU interrupt enable bit.</P
></LI
><LI
><P
>A feature that many HALs support is the ability to execute DSRs on the
interrupt stack. This is not an essential feature, and is better left
unimplemented in the initial porting effort. If this is required, then
the macro <TT
CLASS="LITERAL"
>HAL_INTERRUPT_STACK_CALL_PENDING_DSRS()</TT
>
should be defined to call a function in
<TT
CLASS="FILENAME"
>vectors.S</TT
>.</P
></LI
><LI
><P
>Define the interrupt and VSR attachment macros. If the same arrays as
for other HALs have been used for VSR and interrupt vectors, then
these macro can be copied across unchanged.</P
></LI
></UL
></LI
><LI
><P
>A number of other header files also need to be filled in:</P
><P
></P
><UL
><LI
><P
><TT
CLASS="FILENAME"
>basetype.h</TT
>. This file defines the basic types
used by eCos, together with the endianness and some other
characteristics. This file only really needs to contain definitions
if the architecture differs significantly from the defaults defined
in <TT
CLASS="FILENAME"
>cyg_type.h</TT
></P
></LI
><LI
><P
><TT
CLASS="FILENAME"
>hal_io.h</TT
>. This file contains macros for accessing
device IO registers. If the architecture uses memory mapped IO, then
these can be copied unchanged from an existing HAL such as MIPS. If
the architecture uses special IO instructions, then these macros must
be defined as inline assembler fragments. See the I386 HAL for an
example. PCI bus access macros are usually defined in the variant or
platform HALs.</P
></LI
><LI
><P
><TT
CLASS="FILENAME"
>hal_cache.h</TT
>. This file contains cache access
macros. If the architecture defines cache instructions, or control
registers, then the access macros should be defined here. Otherwise
they must be defined in the variant or platform HAL. Usually the cache
dimensions (total size, line size, ways etc.) are defined in the
variant HAL.</P
></LI
><LI
><P
><TT
CLASS="FILENAME"
>arch.inc</TT
> and
<TT
CLASS="FILENAME"
>&lt;architecture&gt;.inc</TT
>. These files are
assembler headers used by <TT
CLASS="FILENAME"
>vectors.S</TT
> and
<TT
CLASS="FILENAME"
>context.S</TT
>.
<TT
CLASS="FILENAME"
>&lt;architecture&gt;.inc</TT
> is a general purpose
header that should contain things like register aliases, ABI
definitions and macros useful to general assembly
code. If there are no such definitions, then this file need not be
provided. <TT
CLASS="FILENAME"
>arch.inc</TT
> contains macros for performing
various eCos related operations such as initializing the CPU, caches,
FPU etc. The definitions here may often be configured or overridden by
definitions in the variant or platform HALs. See the MIPS HAL for an
example of this.</P
></LI
></UL
></LI
><LI
><P
>Write <TT
CLASS="FILENAME"
>vectors.S</TT
>. This is the most important file
in the HAL. It contains the CPU initialization code, exception and
interrupt handlers. While other HALs should be consulted for
structures and techniques, there is very little here that can be
copied over without major edits.</P
><P
>The main pieces of code that need to be defined here are:</P
><P
></P
><UL
><LI
><P
>Reset vector. This usually need to be positioned at the start of the
ROM or FLASH, so should be in a linker section of its own. It can then be
placed correctly by the linker script. Normally this code is little
more than a jump to the label <TT
CLASS="LITERAL"
>_start</TT
>.</P
></LI
><LI
><P
>Exception vectors. These are the trampoline routines connected to the
hardware exception entry points that vector through the VSR table. In
many architectures these are adjacent to the reset vector, and should
occupy the same linker section. If the architecture allow the vectors
to be moved then it may be necessary for these trampolines to be
position independent so they can be relocated at runtime.</P
><P
>The trampolines should do the minimum necessary to transfer control
from the hardware vector to the VSR pointed to by the matching table
entry. Exactly how this is done depends on the architecture. Usually
the trampoline needs to get some working registers by either saving
them to CPU special registers (e.g. PowerPC SPRs), using reserved
general registers (MIPS K0 and K1), using only memory based
operations (IA32), or just jumping directly (ARM). The VSR table index
to be used is either implicit in the entry point taken (PowerPC, IA32,
ARM), or must be determined from a CPU register (MIPS).</P
></LI
><LI
><P
>Write kernel startup code. This is the location the reset vector jumps
to, and can be in the main text section of the executable, rather than
a special section. The code here should first initialize the CPU and other
hardware subsystems. The best approach is to use a set of macro
calls that are defined either in <TT
CLASS="FILENAME"
>arch.inc</TT
> or
overridden in the variant or platform HALs. Other jobs that this code
should do are: initialize stack pointer; copy the data section from
ROM to RAM if necessary; zero the BSS; call variant and platform
initializers; call <TT
CLASS="FUNCTION"
>cyg_hal_invoke_constructors()</TT
>;
call <TT
CLASS="FUNCTION"
>initialize_stub()</TT
> if necessary. Finally it
should call <TT
CLASS="FUNCTION"
>cyg_start()</TT
>. See <A
HREF="hal-exception-handling.html#HAL-STARTUP"
>the Section called <I
>HAL Startup</I
> in Chapter 10</A
> for details.</P
></LI
><LI
><P
>Write the default exception VSR. This VSR is installed in the VSR
table for all synchronous exception vectors. See <A
HREF="hal-default-synchronous-exception-handling.html"
>the Section called <I
>Default Synchronous Exception Handling</I
> in Chapter 10</A
> for details of
what this VSR does.</P
></LI
><LI
><P
>Write the default interrupt VSR. This is installed in all VSR table
entries that correspond to external interrupts. See <A
HREF="hal-default-synchronous-exception-handling.html"
>the Section called <I
>Default Synchronous Exception Handling</I
> in Chapter 10</A
> for details of
what this VSR does.</P
></LI
><LI
><P
>Write
<TT
CLASS="FUNCTION"
>hal_interrupt_stack_call_pending_dsrs()</TT
>. If this
function is defined in <TT
CLASS="FILENAME"
>hal_arch.h</TT
> then it should
appear here. The purpose of this function is to call DSRs on the
interrupt stack rather than the current thread's stack. This is not an
essential feature, and may be left until later. However it interacts
with the stack switching that goes on in the interrupt VSR, so it may
make sense to write these pieces of code at the same time to ensure
consistency.</P
><P
>When this function is implemented it should do the following:</P
><P
></P
><UL
><LI
><P
>Take a copy of the current SP and then switch to the interrupt stack.</P
></LI
><LI
><P
>Save the old SP, together with the CPU status register (or whatever
register contains the interrupt enable status) and any other
registers that may be corrupted by a function call (such as any link
register) to locations in the interrupt stack.</P
></LI
><LI
><P
>Enable interrupts.</P
></LI
><LI
><P
>Call <TT
CLASS="FUNCTION"
>cyg_interrupt_call_pending_DSRs()</TT
>. This is a
kernel functions that actually calls any pending DSRs.</P
></LI
><LI
><P
>Retrieve saved registers from the interrupt stack and switch back to
the current thread stack.</P
></LI
><LI
><P
>Merge the interrupt enable state recorded in the save CPU status
register with the current value of the status register to restore the
previous enable state. If the status register does not contain any
other persistent state then this can be a simple restore of the
register. However if the register contains other state bits that might
have been changed by a DSR, then care must be taken not to disturb
these.</P
></LI
></UL
></LI
><LI
><P
>Define any data items needed. Typically <TT
CLASS="FILENAME"
>vectors.S</TT
>
may contain definitions for the VSR table, the interrupt tables and the
interrupt stack. Sometimes these are only default definitions that may
be overridden by the variant or platform HALs.</P
></LI
></UL
></LI
><LI
><P
>Write <TT
CLASS="FILENAME"
>context.S</TT
>. This file contains the context
switch code. See <A
HREF="hal-architecture-characterization.html#HAL-CONTEXT-SWITCH"
>the Section called <I
>Thread Context Switching</I
> in Chapter 9</A
> for details of
how these functions operate. This file may also contain the
implementation of <TT
CLASS="FUNCTION"
>hal_setjmp()</TT
> and
<TT
CLASS="FUNCTION"
>hal_longjmp()</TT
>.</P
></LI
><LI
><P
>Write <TT
CLASS="FILENAME"
>hal_misc.c</TT
>. This file contains any C
data and functions needed by the HAL. These might include:</P
><P
></P
><UL
><LI
><P
><TT
CLASS="VARNAME"
>hal_interrupt_*[]</TT
>. In some HALs, if these arrays
are not defined in <TT
CLASS="FILENAME"
>vectors.S</TT
> then they must be
defined here.</P
></LI
><LI
><P
><TT
CLASS="FUNCTION"
>cyg_hal_exception_handler()</TT
>. This function is
called from the exception VSR. It usually does extra decoding of the
exception and invokes any special handlers for things like FPU traps,
bus errors or memory exceptions. If there is nothing special to be
done for an exception, then it either calls into the GDB stubs, by
calling <TT
CLASS="FUNCTION"
>__handle_exception()</TT
>, or
invokes the kernel by calling
<TT
CLASS="FUNCTION"
>cyg_hal_deliver_exception()</TT
>.</P
></LI
><LI
><P
><TT
CLASS="FUNCTION"
>hal_arch_default_isr()</TT
>. The
<TT
CLASS="VARNAME"
>hal_interrupt_handlers[]</TT
> array is usually
initialized with pointers to <TT
CLASS="FILENAME"
>hal_default_isr()</TT
>,
which is defined in the common HAL. This function handles things like
Ctrl-C processing, but if that is not relevant, then it will call
<TT
CLASS="FUNCTION"
>hal_arch_default_isr()</TT
>. Normally this function
should just return zero.</P
></LI
><LI
><P
><TT
CLASS="FUNCTION"
>cyg_hal_invoke_constructors()</TT
>. This calls the
constructors for all static objects before the program starts. eCos
relies on these being called in the correct order for it to function
correctly. The exact way in which constructors are handled may differ
between architectures, although most use a simple table of function
pointers between labels <TT
CLASS="LITERAL"
>__CTOR_LIST__</TT
> and
<TT
CLASS="LITERAL"
>__CTOR_END__</TT
> which must called in order from the
top down. Generally, this function can be copied directly from an
existing architecture HAL.</P
></LI
><LI
><P
>Bit indexing functions. If the macros
<TT
CLASS="LITERAL"
>HAL_LSBIT_INDEX()</TT
> and
<TT
CLASS="LITERAL"
>HAL_MSBIT_INDEX()</TT
> are defined as function calls,
then the functions should appear here. The main reason for doing this
is that the architecture does not have support for bit indexing and
these functions must provide the functionality by conventional
means. While the trivial implementation is a simple for loop, it is
expensive and non-deterministic. Better, constant time,
implementations can be found in several HALs (MIPS for example).</P
></LI
><LI
><P
><TT
CLASS="FUNCTION"
>hal_delay_us()</TT
>. If the macro
<TT
CLASS="LITERAL"
>HAL_DELAY_US()</TT
> is defined in <TT
CLASS="FILENAME"
>hal_intr.h</TT
> then it should be defined to
call this function. While most of the time this function is called
with very small values, occasionally (particularly in some ethernet
drivers) it is called with values of several seconds. Hence the
function should take care to avoid overflow in any calculations.</P
></LI
><LI
><P
><TT
CLASS="FUNCTION"
>hal_idle_thread_action()</TT
>. This function is called
from the idle thread via the
<TT
CLASS="LITERAL"
>HAL_IDLE_THREAD_ACTION()</TT
> macro, if so
defined. While normally this function does nothing, during development
this is often a good place to report various important system
parameters on LCDs, LED or other displays. This function can also
monitor system state and report any anomalies. If the architecture
supports a <TT
CLASS="LITERAL"
>halt</TT
> instruction then this is a good
place to put an inline assembly fragment to execute it. It is also a
good place to handle any power saving activity.</P
></LI
></UL
></LI
><LI
><P
>Create the <TT
CLASS="FILENAME"
>&lt;architecture&gt;.ld</TT
> file. While
this file may need to be moved to the variant HAL in the future, it
should initially be defined here, and only moved if necessary.</P
><P
>This file defines a set of macros that are used by the platform
<TT
CLASS="LITERAL"
>.ldi</TT
> files to generate linker scripts. Most GCC
toolchains are very similar so the correct approach is to copy the
file from an existing architecture and edit it. The main things that
will need editing are the <TT
CLASS="LITERAL"
>OUTPUT_FORMAT()</TT
> directive
and maybe the creation or allocation of extra sections to various
macros. Running the target linker with just the
<TT
CLASS="LITERAL"
>--verbose</TT
> argument will cause it to output its
default linker script. This can be compared with the
<TT
CLASS="LITERAL"
>.ld</TT
> file and appropriate edits made.</P
></LI
><LI
><P
>If GDB stubs are to be supported in RedBoot or eCos, then support must
be included for these. The most important of these are <TT
CLASS="FILENAME"
>include/&lt;architecture&gt;-stub.h</TT
> and
<TT
CLASS="FILENAME"
>src/&lt;architecture&gt;-stub.c</TT
>. In all existing
architecture HALs these files, and any support files they need, have
been derived from files supplied in <TT
CLASS="LITERAL"
>libgloss</TT
>, as
part of the GDB toolchain package. If this is a totally new
architecture, this may not have been done, and they must be created
from scratch.</P
><P
><TT
CLASS="FILENAME"
>include/&lt;architecture&gt;-stub.h</TT
>
contains definitions that are used by the GDB stubs to describe the
size, type, number and names of CPU registers. This information is
usually found in the GDB support files for the architecture. It also
contains prototypes for the functions exported by
<TT
CLASS="FILENAME"
>src/&lt;architecture&gt;-stub.c</TT
>; however, since
this is common to all architectures, it can be copied from some other
HAL.</P
><P
><TT
CLASS="FILENAME"
>src/&lt;architecture&gt;-stub.c</TT
> implements the
functions exported by the header. Most of this is fairly straight
forward: the implementation in existing HALs should show exactly what
needs to be done. The only complex part is the support for
single-stepping. This is used a lot by GDB, so it cannot be
avoided. If the architecture has support for a trace or single-step
trap then that can be used for this purpose. If it does not then this
must be simulated by planting a breakpoint in the next
instruction. This can be quite involved since it requires some
analysis of the current instruction plus the state of the CPU to
determine where execution is going to go next.</P
></LI
></OL
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="HAL-PORTING-ARCHITECTURE-CDL">CDL Requirements</H2
><P
>The CDL needed for any particular architecture HAL depends to a large
extent on the needs of that architecture. This includes issues such as
support for different variants, use of FPUs, MMUs and caches. The
exact split between the architecture, variant and platform HALs for
various features is also somewhat fluid. </P
><P
>To give a rough idea about how the CDL for an architecture is
structured, we will take as an example the I386 CDL.</P
><P
>This first section introduces the CDL package and placed it under the
main HAL package. Include files from this package will be put in the
<TT
CLASS="FILENAME"
>include/cyg/hal</TT
> directory, and definitions from
this file will be placed in
<TT
CLASS="FILENAME"
>include/pkgconf/hal_i386.h</TT
>. The
<TT
CLASS="LITERAL"
>compile</TT
> line specifies the files in the
<TT
CLASS="FILENAME"
>src</TT
> directory that are to be compiled as part of
this package.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>cdl_package CYGPKG_HAL_I386 {
    display       "i386 architecture"
    parent        CYGPKG_HAL
    hardware
    include_dir   cyg/hal
    define_header hal_i386.h
    description   "
        The i386 architecture HAL package provides generic
        support for this processor architecture. It is also
        necessary to select a specific target platform HAL
        package."
 
    compile       hal_misc.c context.S i386_stub.c hal_syscall.c</PRE
></TD
></TR
></TABLE
><P
>Next we need to generate some files using non-standard make rules. The
first is <TT
CLASS="FILENAME"
>vectors.S</TT
>, which is not put into the
library, but linked explicitly with all applications. The second is
the generation of the <TT
CLASS="FILENAME"
>target.ld</TT
> file from
<TT
CLASS="FILENAME"
>i386.ld</TT
> and the startup-selected
<TT
CLASS="FILENAME"
>.ldi</TT
> file. Both of these are essentially
boilerplate code that can be copied and edited.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13;    make {
        &lt;PREFIX&gt;/lib/vectors.o : &lt;PACKAGE&gt;/src/vectors.S
        $(CC) -Wp,-MD,vectors.tmp $(INCLUDE_PATH) $(CFLAGS) -c -o $@ $&lt;
        @echo $@ ": \\" &gt; $(notdir $@).deps
        @tail +2 vectors.tmp &gt;&gt; $(notdir $@).deps
        @echo &gt;&gt; $(notdir $@).deps
        @rm vectors.tmp
    }
 
    make {
        &lt;PREFIX&gt;/lib/target.ld: &lt;PACKAGE&gt;/src/i386.ld
        $(CC) -E -P -Wp,-MD,target.tmp -DEXTRAS=1 -xc $(INCLUDE_PATH) $(CFLAGS) -o $@ $&lt;
        @echo $@ ": \\" &gt; $(notdir $@).deps
        @tail +2 target.tmp &gt;&gt; $(notdir $@).deps
        @echo &gt;&gt; $(notdir $@).deps
        @rm target.tmp
    }</PRE
></TD
></TR
></TABLE
><P
>The i386 is currently the only architecture that supports SMP. The
following CDL simply enabled the HAL SMP support if
required. Generally this will get enabled as a result of a
<TT
CLASS="LITERAL"
>requires</TT
> statement in the kernel. The
<TT
CLASS="LITERAL"
>requires</TT
> statement here turns off lazy FPU
switching in the FPU support code, since it is inconsistent with SMP
operation.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13;    cdl_component CYGPKG_HAL_SMP_SUPPORT {
	display       "SMP support"
	default_value 0
	requires { CYGHWR_HAL_I386_FPU_SWITCH_LAZY == 0 }
 
	cdl_option CYGPKG_HAL_SMP_CPU_MAX {
	    display       "Max number of CPUs supported"
	    flavor        data
	    default_value 2
	}
    }</PRE
></TD
></TR
></TABLE
><P
>The i386 HAL has optional FPU support, which is enabled by default. It
can be disabled to improve system performance. There are two FPU
support options: either to save and restore the FPU state on every
context switch, or to only switch the FPU state when necessary.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>        
    cdl_component CYGHWR_HAL_I386_FPU {
	display       "Enable I386 FPU support"
	default_value 1
	description   "This component enables support for the
	              I386 floating point unit."
 
	cdl_option CYGHWR_HAL_I386_FPU_SWITCH_LAZY {
	    display       "Use lazy FPU state switching"
	    flavor        bool
	    default_value 1
 
	    description "
	                This option enables lazy FPU state switching.
                        The default behaviour for eCos is to save and
                        restore FPU state on every thread switch, interrupt
	                and exception. While simple and deterministic, this
	                approach can be expensive if the FPU is not used by
	                all threads. The alternative, enabled by this option,
	                is to use hardware features that allow the FPU state
	                of a thread to be left in the FPU after it has been
	                descheduled, and to allow the state to be switched to
	                a new thread only if it actually uses the FPU. Where
	                only one or two threads use the FPU this can avoid a
	                lot of unnecessary state switching."
	}
    }</PRE
></TD
></TR
></TABLE
><P
>The i386 HAL also has support for different classes of CPU. In
particular, Pentium class CPUs have extra functional units, and some
variants of GDB expect more registers to be reported. These options
enable these features. Generally these are enabled by
<TT
CLASS="LITERAL"
>requires</TT
> statements in variant or platform
packages, or in <TT
CLASS="LITERAL"
>.ecm</TT
> files.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13;    cdl_component CYGHWR_HAL_I386_PENTIUM {
	display       "Enable Pentium class CPU features"
	default_value 0
	description   "This component enables support for various
	              features of Pentium class CPUs."
 
	cdl_option CYGHWR_HAL_I386_PENTIUM_SSE {
	    display       "Save/Restore SSE registers on context switch"
	    flavor        bool
	    default_value 0
 
	    description "
	                This option enables SSE state switching. The default
                        behaviour for eCos is to ignore the SSE registers.
                        Enabling this option adds SSE state information to
                        every thread context."
	}
 
	cdl_option CYGHWR_HAL_I386_PENTIUM_GDB_REGS {
	    display       "Support extra Pentium registers in GDB stub"
	    flavor        bool
	    default_value 0
 
	    description "
	                This option enables support for extra Pentium registers
			in the GDB stub. These are registers such as CR0-CR4, and
                        all MSRs. Not all GDBs support these registers, so the
                        default behaviour for eCos is to not include them in the
			GDB stub support code."
	}
    }</PRE
></TD
></TR
></TABLE
><P
>In the i386 HALs, the linker script is provided by the architecture
HAL. In other HALs, for example MIPS, it is provided in the variant
HAL. The following option provides the name of the linker script to
other elements in the configuration system.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>    cdl_option CYGBLD_LINKER_SCRIPT {
        display "Linker script"
        flavor data
	no_define
        calculated  { "src/i386.ld" }
    }</PRE
></TD
></TR
></TABLE
><P
>Finally, this interface indicates whether the platform supplied an
implementation of the
<TT
CLASS="FUNCTION"
>hal_i386_mem_real_region_top()</TT
> function. If it
does then it will contain a line of the form: <TT
CLASS="LITERAL"
>implements
CYGINT_HAL_I386_MEM_REAL_REGION_TOP</TT
>. This allows packages
such as RedBoot to detect the presence of this function so that they
may call it.</P
><TABLE
BORDER="5"
BGCOLOR="#E0E0F0"
WIDTH="70%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13;    cdl_interface CYGINT_HAL_I386_MEM_REAL_REGION_TOP {
        display  "Implementations of hal_i386_mem_real_region_top()"
    }
 
}</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="hal-porting-variant.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="ecos-ref.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="hal-future-developments.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Variant HAL Porting</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="hal-porting-guide.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Future developments</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.