Introduction | - | - | The Boards/<boardname> directory contains the modules which provide
board & processor specific code for a particular port of NedHAL. While Core/ARM
contains only the ARM processor specific code (which is still portable across
implementations of the ARM), the ARM board definition modules provide board-specific code
and definitions required by the other parts of NedHAL to successfully run upon this
particular configuration. To be specific, this includes:
|
|
General use | This is effectively the specific board 'port' of NedHAL to an ARM
architecture board. You will at the very minimum need to rewrite two header files to port
NedHAL to a new board (that being the ARM assembler and ANSI C variants of the same
information). In addition, you may need to write additional modules (also housed in here)
to drive non-industry standard peripheral hardware. Of course, all industry-standard
hardware driver code should be written in portable code and housed somewhere outside the
Boards directory. Of course, given that boards will have wildly differing capabilities and configurations, the content provided by the board definition modules will also wildly vary. This chapter documents the absolute minimum required of a board definition module. On ARM board definitions, one needs to write a BoardDefinesH.s which is a header file included by the Core/ARM files. You also must write a BoardDefines.h file which mirrors the content of BoardDefinesH.s for C code. You will also need to write modules to drive board-specific things like timers or LEDs - these may be in ARM assembler or C, whichever you choose. The best way of porting to a new board is to take an existing board definition file and alter it. You will find it extensively documented internally to aid quick porting. |
|||
Porting to "tiny" systems | Upon startup, NedHAL always has access to a zero page, an area
of volatile memory used by many NedHAL modules to store their data. Typically this memory
is on-chip static memory or otherwise. It then configures DRAM for use, copies static C
data into the bottom of memory and places the program stack (R13_usr32) at the top of
memory (as set by BOARD_SETUPMEMORYSYSTEM). On tiny systems with 4Kb of DRAM or more, one must integrate the zero page, static data and User32 program stack into the same 4Kb. To do thus, decrease and shuffle around the generous sizes given to the processor supervisor stacks. Set the ARM linker to place the data within the zero page and make space in the zero page for it to fit (don't forget zero-initialised data). And then change the values for bottom and top of memory returned by BOARD_SETUPMEMORYSYSTEM to the start and end of the zero page. You can determine the size of static C data by subtracting the values of the linker symbols Image$$RW$$Base from Image$$ZI$$Limit (use the ARM debugger to determine these through its list low level symbols operation) |
Purpose | - | - | Defines memory layout and the sizes of certain structures | |||||||||||||||||||||||||||||||||||
Use | The Core/ARM/ExceptH module permits the installation of a certain amount
of handlers per ARM exception vector. The number of these handlers is specified in
BoardDefines:
You may specify zero for the number of handlers, but then it is your responsibility to install a handler for that exception. Furthermore, you must ensure that exception is not triggered prior to your installing a handler for it. You must also specify the sizes of the stacks for each of the ARM processor supervisor modes (IRQ32, FIQ32, Abort32, Undef32 and SVC32):
Furthermore, you must specify the layout of the HAL zero page. The HAL zero page is used as storage by many HAL modules - it is some form of alterable memory available to the HAL from start-up. Most embedded systems will have at least 1k of storage space immediately available to the processor from startup without the need of any setup code - this is ideal for storing the HAL zero page (even if only temporarily). The layout and contents of the zero page is definable by you, and hence may occupy as much or as little space as you desire:
Some of these may change according to debug or standalone builds. If a standalone build is being made, STANDALONE is defined. If the ARM debuggers Angel or Demon are being used to debug a debug build, then ANGEL or DEMON is defined respectively. Use conditional compilation to change memory layouts according build type. Finally, you must map out where all the possible UART driver context blocks will live within zero page (if at all) which is of course defined by BOARD_HALZP_UARTSPACE above. Typically, these will follow the format: AT91AUARTID EQU 2 AT91AUARTADDR EQU 0xFFFD0000 HALZP_AT91AUARTSPACE EQU (AT91AUARTID * HALUARTBLK_SIZEOF) This is the definition of a serial UART called AT91A. The ID is the index of the number of structures into the zero page UART space - so, for example, the first UART context would be 0, the next 1, the next 2 etc. You see how this works as HALZP_AT91AUARTSPACE is set to the ID multiplied by the size of the UART context structure, HALUARTBLK_SIZEOF. To maintain good form, the UART hardware address is also specified here (as AT91UARTADDR) to aid ease of changing the hardware in the future - however, your UART may not need this. |
Purpose | - | - | Sets the state of the debug LEDs on the board | |
Entry | $reg = ARM register containing bitmap of on/off state of LEDs | |||
Exit | R0-R3 corrupted | |||
Interrupts | IRQ is unchanged FIQ is unchanged |
|||
Processor Mode | Unchanged | |||
Staticity | Depends on implementation | |||
Use | This macro assembles code to change the state of the debug LEDs on the board based on parameter $reg. It is up to you how to map bits to LEDs. Of course, you may leave this macro empty if there are no LEDs. | |||
Notes | See the documentation accompanying your specific hardware for more information about implementing this macro |
Purpose | - | - | Remaps ROM from boot location to normal location | |
Entry | None | |||
Exit | R0-R14 corrupted Also PC may be offset |
|||
Interrupts | IRQ is disabled FIQ is disabled |
|||
Processor Mode | SVC32 | |||
Staticity | Not static | |||
Use | This macro assembles code to remap ROM from boot location to normal
location. At boot on most ARM implementations, ROM is mapped to 0x00000000 so that when
the ARM starts up it reads initially from ROM. However, if one wishes to soft-install
handlers for the ARM exception vectors one must map DRAM to 0x00000000 and remap ROM to
somewhere. On ARM's with an MMU and 16k of space to store L1 page tables, this is easy. However, for smaller embedded implementations there simply isn't enough space so a hardware solution is provided which allows a write to a register to remap ROM and replace it with RAM. The ARM's three stage pipeline is used to offset the program counter by the required amount in the instruction just postceding the write to the hardware register. Hence on exit from this macro the program counter may be many megabytes from where it was. The exact nature of the code required to perform this remap is outside the scope of this manual. However, NedHAL does not require RAM to exist at 0x00000000 and hence for an initial port you may not need to place any code in this macro. |
|||
Notes | See the documentation accompanying your specific hardware for more
information about implementing this macro. Note also that this macro's contents are not used in debug builds of NedHAL |
Purpose | - | - | Configures the DRAM controller for subsequent use of DRAM | |
Entry | None | |||
Exit | R0-R14 corrupted | |||
Interrupts | IRQ is disabled FIQ is disabled |
|||
Processor Mode | SVC32 | |||
Staticity | Not static | |||
Use | This macro assembles code to configure the DRAM controller for subsequent
use of DRAM memory. Typical items include enabling power to DRAM, setting up refresh
cycles, width of data access and wait states. When this macro exits, DRAM should be fully accessible. NedHAL subsequent to this sets up the User32 stack at the end of DRAM and copies static C and assembler data into the start of DRAM (on STANDALONE builds only - debug builds vary) |
|||
Notes | See the documentation accompanying your specific hardware for more
information about implementing this macro. Note also that this macro's contents are not used in debug builds of NedHAL |
Purpose | - | - | Returns the location of the HAL zero page | |
Entry | $reg = register to receive address of HAL zero page | |||
Exit | All registers but $reg preserved | |||
Interrupts | IRQ is unchanged FIQ is unchanged |
|||
Processor Mode | Unchanged | |||
Staticity | Fully static | |||
Use | This macro assembles code to return the address of the HAL zero page.
This macro is used extensively throughout NedHAL (including the interrupt handlers) and
hence must contain extremely quick code. The location of the zero page is left entirely up to you. See the Miscellaneous section above for tips concerning location, size and layout of the HAL zero page. |
|||
Notes | See the documentation accompanying your specific hardware for more
information about implementing this macro. The value returned by this macro may vary according to debug or standalone builds. |
Purpose | - | - | Sets up the memory system for the board | |
Entry | None | |||
Exit | R0-R14 corrupted | |||
Interrupts | IRQ is disabled FIQ is disabled |
|||
Processor Mode | SVC32 | |||
Staticity | Not static | |||
Use | This macro assembles code to set up the memory system for the board and
is typically called just after the DRAM controller has been set up and DRAM is available.
Typical actions carried out by this macro include:
The ARM control modules ARMCore, ARMCache and ARMMMU have API's to help you in writing this macro. To write the base and top of DRAM, write members HALZP_DRAMBASE and HALZP_DRAMTOP within the HAL zero page with suitable addresses. |
|||
Notes | See the documentation accompanying your specific hardware for more information about implementing this macro. |
Purpose | - | - | Disables an unclaimed interrupt request | |
Entry | None | |||
Exit | R0-R3 corrupted | |||
Interrupts | IRQ is disabled FIQ may be disabled if source is FIQ |
|||
Processor Mode | IRQ32 or FIQ32 | |||
Staticity | Not static | |||
Use | This macro assembles code called by the ARM/ExceptH module to disable an
unknown interrupt. If the ExceptH interrupt handler encounters an interrupt which isn't
claimed by any of the currently installed handlers, it calls the code assembled by this
macro to determine what interrupt source generated the interrupt and to disable that
interrupt. Failing to disable the unknown interrupt may cause the interrupt exception handler code to be reentered immediately on exit from the handler, thus locking up the machine. |
|||
Notes | See the documentation accompanying your specific hardware for more information about implementing this macro. |
Purpose | - | - | Initialises the board prior to passing control the operating system | |
Entry | None | |||
Exit | R0-R3 corrupted | |||
Interrupts | IRQ is enabled FIQ is enabled |
|||
Processor Mode | User32 | |||
Staticity | Not static | |||
Use | This macro assembles code to perform post-boot board initialisation. You
may call C based code at this stage as the C runtime system has been initialised, stacks
and interrupt handlers setup etc. In fact, this macro's code is called just prior to
calling NedHAL_Entry, the entry point into the operating system. Typical things to do here are to initialise board modules eg; propriatery timer driver modules. One might also set up debug output through the DebugIO module to use propriatery serial UART driver modules. |
|||
Notes | None |
Purpose | - | - | Finalises the board should the operating system return control | |
Entry | None | |||
Exit | R0-R3 corrupted | |||
Interrupts | IRQ is enabled FIQ is enabled |
|||
Processor Mode | User32 | |||
Staticity | Not static | |||
Use | This macro assembles code to perform finalisation should the operating system ever return control from the NedHAL_Entry function. Typically one would finalise modules initialised in BOARD_INITIALISE. | |||
Notes | None |