The ARM board definition modules

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:

  • Definitions valid for this architecture and board
    Every board has its own way of initialising (eg; powering up and configuring DRAM or remapping ROM from boot location to normal location). Actual ARM code to do this must be provided.
  • Layout and location of data within memory
    Primarily, you must specify the location of the HAL zero page and subsequently locations of various things within that zero page. Also, processor stacks and MMU page table locations and of course code to determine size and location of DRAM is required.
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)

 

Miscellaneous definitions

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:

UndefinedExcptHandlers The number of handlers for the Undefined Instruction exception
SWIExcptHandlers The number of handlers for the SWI exception
PAbortExcptHandlers The number of handlers for the Abort on Instruction Fetch exception
DAbortExcptHandlers The number of handlers for the Abort on Data Fetch exception
IRQExcptHandlers The number of handlers for the Interrupt Request exception
FIQExcptHandlers The number of handlers for the Fast Interrupt Request exception

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):

IRQ32StackSize The number of bytes to allocate for the IRQ32 stack
FIQ32StackSize The number of bytes to allocate for the FIQ32 stack
Abort32StackSize The number of bytes to allocate for the Abort32 stack
Undef32StackSize The number of bytes to allocate for the Undef32 stack
SVC32StackSize The number of bytes to allocate for the SVC32 stack

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:

BOARD_EXCEPTHLOCATION Offset within zero page of the ARM exception vectors (useful if you remap on-chip static RAM to 0x0 in order that it may hold soft copies of the ARM exception vectors and you also wish to store the HAL zero page there)
BOARD_HALZPLOCATION Offset within zero page of HAL volatile information (HALZP_HALZPEND within Core/ARM/CommonH.s gives size of this entry)
BOARD_HALZP_UARTSPACE Offset within zero page of UART driver context blocks (size determined by entries below)
BOARD_ARMMMU_L1PAGETABLES Offset within zero page of ARM MMU L1 page tables. Note these are exactly 16k long on v3 and v4 revisions of the ARM architecture. You may leave this undefined if you don't set up ARM MMU tables in the zero page.
BOARD_HALSTKSLOCATION Offset within zero page of the ARM processor supervisor stacks whose sizes are as defined above
BOARD_HALZP_SIZEOF Size in bytes of the entire HAL zero page (obviously ensure this fits into whatever DRAM you are placing the zero page). This value must be the same as sizeof(HALZeroPage).

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.

 

BOARD_SETLEDS

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

 

BOARD_MOVEROM

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

 

BOARD_INITIALISEDRAM

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

 

BOARD_RETURNZPLOCATION

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.

 

BOARD_SETUPMEMORYSYSTEM

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:
  • Determining the memory configuration of the board (eg; size of memory, whether it is contiguous or not)
  • Building ARM MMU page tables to remap physical memory into a more desirable form (STANDALONE builds only)
  • Enabling ARM MMU, write-buffering, caching and other performance features
  • Setting locations of the base and top of DRAM

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.

 

BOARD_DISABLEUNKNOWNINTERRUPT

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.

 

BOARD_INITIALISE

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

 

BOARD_FINALISE

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