The ARM support modules

Introduction - - The Core/ARM directory contains the modules which provide support for the ARM processor. It comprises of all the non-board-specific ARM-related code within NedHAL.

To be specific, this includes:

  • Definitions valid for the ARM architecture
    The portable parts of NedHAL written in C need to know the definition of (say) a signed 32 bit integer, along with definitions of many other sizes (s64, u16, s8 etc)
  • ARMCore, ARMCache and ARMMMU modules for each revision of the ARM architecture
    These modules provide ARM processor control code on a generic ARM-wise basis
  • ARM processor exception handling (ExceptH module)
    As with all microprocessors, external events need to be handled by the ARM. The ExceptH provides a portable way of handling processor exceptions which does not sacrifice speed or functionality
Overview This is effectively the ARM 'port' of NedHAL and it resides within Core/ARM. It should come as part of the NedHAL distribution.

For the ARM-specific documentation, there are a number of extra fields added to the standard API description as given in the manual introduction to extend it for real-time and embedded use on the ARM processor. Here is a complete API field explanation, but with the new fields in white:

<module prefix>_<api postfix>

Purpose - - This entry tells you what this API does
Entry This entry lists the contents of ARM registers required by this API on entry. You can determine the C prototype from these using APCS rules (APCS is the Arm Procedure Call Standard - the way compilers are implemented on the ARM - see ARM documentation for more information).

While the exact operation of the APCS is outside the scope of this manual, suffice it to say that usually R0 will be the first parameter in C, R1 is the second, R2 is the third etc. The types are determined by what the register's contents are eg;

R0 = pointer to HALError structure
R1 = pointer to zero terminated string

... would become foo(HALError *, char *). Note that this is not always the case, see the APCS regulations for a full discussion.

Exit This entry list the contents of the ARM registers on exit from this API. Typically it will only ever be R0, as the APCS constrains the single return result from C functions to always be in R0 and to maintain interoperability with C code this convention must be maintained.
Interrupts This entry shows what happens to the normal interrupt (IRQ) and fast interrupt (FIQ) status of the ARM during the execution of this API. This is useful for determining if the call is reentrant, its suitablility for being called from an interrupt request handlers or else determining potential interrupt latencies.
Processor Mode This entry shows what ARM processor modes the API will run in. This is useful for determining if the code can be multitasked by a preemptive scheduler (usually context switches may only happen to code running in User32) and hence determining task swap latencies.
Staticity This entry indicates if the function is static ie; it may be called from two different threads simultaneously. It may give more than a simple yes or no answer if the function is static in certain ways or times but not in or at others.
Use This entry describes the parameters taken by the API in detail, emboldening and underlining the first mention of each parameter to aid quick indexing. It also may expand on the detail of using the API and give caveats concerning use.
Notes This entry lists anything to be noted about the use of this API
Staticity of API's NedHAL on the ARM is based on the use of a zero page of DRAM to store volatile information prior to the availability of the main DRAM banks (see the Board Definintion modules manual for further information). Most of the ARM support modules use zero page space, and many of them use it exclusively (ones with "uses zero page only").

On this port of NedHAL to the ARM, there are short periods of time during boot up when main memory is not available as it has not yet been configured for use and hence the C run-time system is not prepared. Hence, any C code which uses static data (ie; is not fully static in the staticity field) will not run correctly. You must only call fully static API's or ones which only use the zero page as this is guaranteed to be available at all times.

This will usually only be of relevence to people porting NedHAL to a new board (ie; rewriting the board definition files) - some API's cannot be used in some macros. Examine the Board Definition modules manual to see which macros this applies to.

Documentation Most of the NedHAL required functionality is encapsulated within modules, and hence is not documented here but in their own files:

However, there are two items which do not easily fit into the modular design framework of NedHAL - that of multiprocessor support and system halting.

Multiprocessor support Nominally, the only multiprocessor support required of any processor is an interlocked memory load and store instruction. This allows the processor to load the contents of a memory location and set the contents of that same location atomically ie; no part of the system may access that memory location in between the load and store. This is the minimum required to implement semaphores to synchronise between multiple processors in a system. NedHAL abstracts the detail of performing this action so that code may be more easily through the CPU_LOADANDSET call, which will usually be implemented as a macro but may be an inlined C function if the compiler requires it.
Halting the system It is often useful within any system to have an end-of-line call suitable for when everything else has gone wrong - much like the infamous Windows' "blue screen of death". Such a call is especially useful for debugging code, and NedHAL provides it as the only call which is not part of a module as it doesn't really have anywhere to fit well. The call, in line with most ports of NedHAL, is NedHAL_EmergencyStop which takes a HALError structure, prints suitable information from it and then halts the system by entering a supervisor mode, disabling interrupts and entering an infinite loop.
Using NedHAL on the ARM These ARM support files were written to be compiled using the ARM Software Development Toolkit (SDT) v2.0 or later. The GNU make utility is also required (supplied for Win32) to use the provided Makefiles as the ARM SDT make utility cannot handle them. You may get a lot of compiler warnings when you use later versions of the SDT as some ARM assembler notation used by NedHAL has become deprecated.

The initial build target as supplied is for the ARM SDT ARMulator utility which soft-emulates an ARM environment on a host machine. We suggest getting this configuration running first before attempting to board-specific ports.

To install NedHAL for the ARM, copy the files off the source disc onto your hard drive. There are two copies of the makefile for NedHAL, NedHAL/MakefileR and NedHAL/MakefileD which are the release and debug builds of NedHAL - rename whichever one you want to build to Makefile (debug is easier initially). You will then need to alter the makefile to suit the locations of your copy of the ARM SDT.

If you are using Win32, you will also need to copy the provided GNU make utility into somewhere referenced by your PATH variable. Now open a command prompt/line if necessary, and run make. NedHAL should compile all its parts into an ARM library file called nedhal.alf in the NedHAL/<build> directory.

NedHAL_Entry You must now link the nedhal library against the standard C library as provided by ARM and against some of your code which must contain an exported function prototyped void NedHAL_Entry(void). This is the point which NedHAL calls when the system has been initialised and the C run-time system is ready.

In a minimal system, this could be the entry point to your application - you have the minimal functionality provided by NedHAL. However, most will want to provide some form of operating system on top of NedHAL.

 

CPU_LOADANDSET

Purpose - - Performs an interlocked load and store operation
Prototype int CPU_LOADANDSET(int *address, int value)
Exit If implemented as a macro, value as on entry, but changed to former contents of address
If implemented an an inlined function, then returns former contents of address
Interrupts IRQ is unchanged
FIQ is unchanged
Processor Mode Unchanged
Staticity Fully static
Use This call performs an atomic load and store operation, storing value at address and setting value to the former contents of address. It returns value to allow use in if() statements eg;
retest:
if(CPU_LOADANDSET(lockaddr, (temp=0))==0)
   /* Lock being examined by other processor */
   goto retest;
else
   /* Lock not being looked at right now, we have gained exclusive access */
   ...
   /* Reset lock to previous value for others to use */
   *lockaddr=temp;
Notes May be implemented as a macro for lower overhead on ARM compilers which support embedded assembler

 

NedHAL_EmergencyStop

Purpose - - Halts the system with the specified error
Entry R0 = pointer to HALError
Exit Never returns
Interrupts IRQ is disabled
FIQ is disabled
Processor Mode SVC32 if User32 on entry, otherwise unchanged
Staticity Not static
Use This call writes a suitable message to DebugIO and then halts the system. If you are running under a debugger, control will return to the debugger. If not, the system enters an infinite loop.

Needless to say, don't use this call unless it's something very critical. It is expected that debug code will make the most use of this call.

Notes This call does not return