eCosTM Reference Manual
Prev | Chapter 7. The eCos Hardware Abstraction Layer (HAL) | Next

# Architectural HAL files

## `hal/ARCH/arch/v1_2_1/include/basetype.h`

This file defines the properties of the base architecture that are used to compile the portable parts of the kernel. It is included automatically by `cyg/infra/cyg_type.h`. The following definitions may be included.

### Byte order

`CYG_BYTEORDER`

  This defines the byte order of the target and must be set to either `CYG_LSBFIRST` or `CYG_MSBFIRST`.

### Label translation

`CYG_LABEL_NAME(name)`

  This is a wrapper used in some C and C++ files which specify labels defined in assembly code or the linker script. It need only be defined if the default implementation in `cyg/kernel/ktypes.h`, which passes the name argument unaltered, is inadequate. The most usual alternative definition of this macro prepends an underscore to the label name. This depends on the labeling convention of the tool set.

### Base types

    	cyg_halint8
    	cyg_halint16
    	cyg_halint32
    	cyg_halint64
    	cyg_halcount8
    	cyg_halcount16
    	cyg_halcount32
    	cyg_halcount64
    	cyg_halbool

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 default types specified in `cyg/infra/cyg_type.h` cannot be used. Note that these are only the base types, they will be composed with `signed` and `unsigned` to form full type specifications.

#### Atomic types

    	cyg_halatomic
    	CYG_ATOMIC

These types are guaranteed to be read or written in a single uninterruptible operation. It is architecture defined what size this type is, but it will be at least a byte.

## `hal/ARCH/arch/v1_2_1/include/hal_arch.h`

This file contains definitions that are related to the basic architecture of the CPU.

### Register save format

    typedef struct HAL_SavedRegisters
    {
    /* architecture-dependent list of registers to be saved */
    } HAL_SavedRegisters;

This structure describes the layout of a saved machine state on the stack. Such states are saved during thread context switches, interrupts and exceptions. Different quantities of state may be saved 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. Where these states are significantly different, this structure should contain a union of the three states.

### Thread context initialization

    	HAL_THREAD_INIT_CONTEXT( sp, arg, entry, id )

This macro initializes a thread"s context so that it may be switched to by `HAL_THREAD_SWITCH_CONTEXT()`. The arguments are:

sp

  A location containing the current value of the thread"s stack pointer. This should be a variable or a structure field. The SP value will be read out of here and an adjusted value written back.

arg

  A value that is passed as the first argument to the entry point function.

entry

  The address of an entry point function. This will be called according the C calling conventions, and the value of `arg` will be passed as the first argument.

id

  A thread id value. This is only used for debugging purposes, it is ORed into the initialization pattern for unused registers 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 space for a register identifier.

### Thread context switching

    HAL_THREAD_SWITCH_CONTEXT( from, to )

This macro implements the thread switch code. The arguments are:

from

  A pointer to a location where the stack pointer of the current thread will be stored.

to

  A pointer to a location from where the stack pointer of the next thread will be read.

The state 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 `*from`. The value in `*to` is then read and the state of the new thread is loaded from it.

Note that interrupts are not disabled during this process, any interrupts that occur will be delivered onto the stack to which the current value of the CPU stack pointer points. Hence the stack pointer should never be invalid, or loaded with a value that might cause the saved state to become corrupted by an interrupt.

### Bit indexing

    HAL_LSBIT_INDEX( mask, index )
    HAL_MSBIT_INDEX( mask, index )

These macros place in `index` the bit index of the least(most) significant bit in mask. Some architectures have instruction level support for one or other of these operations. If no architectural support is available, then these macros may call C functions to do the job.

### Idle thread activity

    HAL_IDLE_THREAD_ACTION( count )

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 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, and may be used to trigger actions at longer intervals than every loop.

### Reorder barrier

    HAL_REORDER_BARRIER()

When optimizing the compiler can reorder code. In some parts of multi-threaded systems, where the order of actions is vital, this can sometimes cause problems. This macro may be inserted into places where reordering should not happen and prevents code being migrated across it by the compiler optimizer. It should be placed between statements that must be executed in the order written in the code.

### Breakpoint support

    HAL_BREAKPOINT( label )
    HAL_BREAKINST
    HAL_BREAKINST_SIZE

These macros provide support for breakpoints.

`HAL_BREAKPOINT()` executes a breakpoint instruction. The label is defined at the breakpoint instruction so that exception code can detect which breakpoint was executed.

`HAL_BREAKINST` contains the breakpoint instruction code as an integer value. `HAL_BREAKINST_SIZE` is the size of that breakpoint instruction in bytes. Together these may be used to place a breakpoint in any code.

### GDB support

    HAL_THREAD_GET_SAVED_REGISTERS( sp, regs )
    HAL_GET_GDB_REGISTERS( regval, regs )
    HAL_SET_GDB_REGISTERS( regs, regval )

These macros provide support for interfacing GDB to the HAL.

`HAL_THREAD_GET_SAVED_REGISTERS()` extracts a pointer to a HAL_SavedRegisters structure 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 pointer to the HAL_SavedRegisters structure to the variable passed as the second argument.

`HAL_GET_GDB_REGISTERS()` translates a register state as saved by the HAL and into a register dump in the format expected by GDB. It takes a pointer to a HAL_SavedRegisters structure in the `regs` argument and a pointer to the memory to contain the GDB register dump in the `regval` argument.

`HAL_SET_GDB_REGISTERS()` translates a GDB format register dump into a the format expected by the HAL. It takes a pointer to the memory containing the GDB register dump in the `regval` argument and a pointer to a HAL_SavedRegisters structure in the `regs` argument.

### Setjmp and longjmp support

    CYGARC_JMP_BUF_SIZE
    hal_jmp_buf[CYGARC_JMP_BUF_SIZE]
    hal_setjmp( hal_jmp_buf env )
    hal_longjmp( hal_jmp_buf env, int val )

These functions provide support for the C `setjmp()` and `longjmp()` functions. Refer to the C library for further information.

## `hal/ARCH/arch/v1_2_1/include/hal_intr.h`

This file contains definitions related to interrupt handling.

### Vector numbers

    CYGNUM_HAL_VECTOR_XXX
    CYGNUM_HAL_VSR_MIN
    CYGNUM_HAL_VSR_MAX
    CYGNUM_HAL_ISR_MIN
    CYGNUM_HAL_ISR_MAX
    CYGNUM_HAL_EXCEPTION_MIN
    CYGNUM_HAL_EXCEPTION_MAX
    CYGNUM_HAL_ISR_COUNT
    CYGNUM_HAL_VSR_COUNT
    CYGNUM_HAL_EXCEPTION_COUNT

All possible interrupt and exception vectors should be specified here, together with maximum and minimum values for range checking.

There are two ranges of numbers, those for the vector service routines and those for the interrupt service routines. The relationship between these two ranges is undefined, and no equivalence should be assumed if vectors from the two ranges coincide.

The VSR vectors correspond to the set of exception vectors that can be delivered by the CPU architecture, many of these will be internal exception traps. The ISR vectors correspond to the set of external interrupts that can be delivered and are usually determined by extra decoding of an interrupt controller by the interrupt VSR.

Where a CPU supports synchronous exceptions, the range of such exceptions allowed are defined by `CYGNUM_HAL_EXCEPTION_MIN` and `CYGNUM_HAL_EXCEPTION_MAX`. The actual exception numbers will normally correspond to the VSR exception range. In future other exceptions generated by the system software (such as stack overflow) may be added.

`CYGNUM_HAL_ISR_COUNT`, `CYGNUM_HAL_VSR_COUNT` and `CYGNUM_HAL_EXCEPTION_COUNT` define the number of ISRs, VSRs and EXCEPTIONs respectively for the purposes of defining arrays etc. There might be a translation from the supplied vector numbers into array offsets. Hence `CYGNUM_HAL_XXX_COUNT` may not simply be `CYGNUM_HAL_XXX_MAX` - `CYGNUM_HAL_XXX_MIN` or `CYGNUM_HAL_XXX_MAX`+1.

### Interrupt state control

    HAL_DISABLE_INTERRUPTS( old )
    HAL_RESTORE_INTERRUPTS( old )
    HAL_ENABLE_INTERRUPTS()
    HAL_QUERY_INTERRUPTS( state )

These macros provide control over the state of the CPUs interrupt mask mechanism. They should normally manipulate a CPU status register to enable and disable interrupt delivery. They should not access an interrupt controller.

`HAL_DISABLE_INTERRUPTS()` disables the delivery of interrupts and stores the original state of the interrupt mask in the variable passed in the `old` argument.

`HAL_RESTORE_INTERRUPTS()` restores the state of the interrupt mask to that recorded in `old`.

`HAL_ENABLE_INTERRUPTS()` simply enables interrupts regardless of the current state of the mask.

`HAL_QUERY_INTERRUPTS()` stores the state of the interrupt mask in the variable passed in the `state` argument.

It is at the HAL implementer’s discretion exactly which interrupts are masked by this mechanism. Where a CPU has more than one interrupt type that may be masked separately (e.g. the ARM"s IRQ and FIQ) only those that can raise DSRs need to be masked here. A separate architecture specific mechanism may then be used to control the other interrupt types.

### ISR and VSR management

    HAL_INTERRUPT_ATTACH( vector, isr, data, object )
    HAL_INTERRUPT_DETACH( vector, isr )
    HAL_VSR_SET( vector, vsr, poldvsr )
    HAL_VSR_GET( vector, pvsr )

These macros manage the attachment of interrupt and vector service routines to interrupt and exception vectors respectively.

`HAL_INTERRUPT_ATTACH()` attaches the ISR, data pointer and object pointer to the given vector. When an interrupt occurs on this 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 arguments respectively.

`HAL_INTERRUPT_DETACH()` detaches the ISR from the vector.

`HAL_VSR_SET()` replaces the VSR attached to the `vector` with the replacement supplied in `vsr`. The old VSR is returned in the location pointed to by `pvsr`.

`HAL_VSR_GET()` assigns a copy of the VSR to the location pointed to by `pvsr`.

### Interrupt controller management

    HAL_INTERRUPT_MASK( vector )
    HAL_INTERRUPT_UNMASK( vector )
    HAL_INTERRUPT_ACKNOWLEDGE( vector )
    HAL_INTERRUPT_CONFIGURE( vector, level, up )
    HAL_INTERRUPT_SET_LEVEL( vector, level )

These macros exert control over any prioritized interrupt controller that is present. If no priority controller exists, then these macros should be empty.

`HAL_INTERRUPT_MASK()` causes the interrupt associated with the given vector to be blocked.

`HAL_INTERRUPT_UNMASK()` causes the interrupt associated with the given vector to be unblocked.

`HAL_INTERRUPT_ACKNOWLEDGE()` acknowledges the current interrupt from the given vector. This is usually executed from the ISR for this vector when it is prepared to allow further interrupts. Most interrupt controllers need some form of acknowledge action before the next interrupt is allowed through. Executing this macro may cause another interrupt to be delivered. Whether this interrupts the current code depends on the state of the CPU interrupt mask.

`HAL_INTERRUPT_CONFIGURE()` provides control over how an interrupt signal is detected. The arguments are:

vector

  The interrupt to be configured.

level

  Set to `true` if the interrupt is detected by level, and `false` if it is edge triggered.

up

  If the interrupt is set to level detect, then if this is `true` it is detected by a high signal level, and if `false` by a low signal level. If the interrupt is set to edge triggered, then if this is `true` it is triggered by a rising edge and if `false` by a falling edge.

`HAL_INTERRUPT_SET_LEVEL()` provides control over the hardware priority of the interrupt. The arguments are:

vector

  The interrupt whose level is to be set.

level

  The priority level to which the interrupt is to set. In some architectures the set interrupt level is also used as an interrupt enable/disable. Hence this function and `HAL_INTERRUPT_MASK()` and `HAL_INTERRUPT_UNMASK()` may interfere with each other.

### Clock control

    HAL_CLOCK_INITIALIZE( period )
    HAL_CLOCK_RESET( vector, period )
    HAL_CLOCK_READ( pvalue )

These macros provide control over a clock or timer device that may be used by the kernel to provide time-out, delay and scheduling services. The clock is assumed to be implemented by some form of counter that is incremented or decremented by some external source and which raises an interrupt when it reaches zero.

`HAL_CLOCK_INITIALIZE()` initializes the clock device to interrupt at the given period. The period is essentially the value used to initialize the clock counter and must be calculated from the clock frequency and the desired interrupt rate.

`HAL_CLOCK_RESET()` re-initializes the clock to provoke the next interrupt. This macro is only really necessary when the clock device needs to be reset in some way after each interrupt.

`HAL_CLOCK_READ()` reads the current value of the clock counter and puts the value in the location pointed to by `pvalue`. The value stored will always be the number of clock ``ticks"" since the last interrupt, and hence ranges between zero and the initial period value.

## `hal/ARCH/arch/v1_2_1/include/hal_io.h`

This file contains definitions for supporting access to device control registers in an architecture neutral fashion.

### Register address

    HAL_IO_REGISTER

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 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 as a structure.

Values of variables and constants of this type will usually be supplied by configuration mechanisms.

### Register read

    HAL_READ_XXX( register, value )
    HAL_READ_XXX_VECTOR( register, buffer, count, stride )

These macros support the reading of I/O registers in various sizes. The XXX component of the name may be UINT8, UINT16, UINT32.

`HAL_READ_XXX()` reads the appropriately sized value from the register and stores it in the variable passed as the second argument.

`HAL_READ_XXX_VECTOR()` reads `count` values of the appropriate size into `buffer`. The `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 will read adjacent registers of the given size. Greater strides will step by larger amounts, to allow for sparsely mapped registers for example.

### Register write

    HAL_WRITE_XXX( register, value )
    HAL_WRITE_XXX_VECTOR( register, buffer, count, stride )

These macros support the writing of I/O registers in various sizes. The `XXX` component of the name may be `UINT8`, `UINT16`, `UINT32`.

`HAL_WRITE_XXX()` writes the appropriately sized value from the variable passed as the second argument stored it in the register.

`HAL_WRITE_XXX_VECTOR()` writes `count` values of the appropriate size from `buffer`. The `stride` controls how the pointer advances through the register space. A stride of zero will write the same register repeatedly, and a stride of one will write adjacent registers of the given size. Greater strides will step by larger amounts, to allow for sparsely mapped registers for example.

## `hal/ARCH/arch/v1_2_1/include/hal_cache.h`

This file contains definitions for supporting control of the caches on the CPU.

There are versions of the macros defined here for both the Data and Instruction caches. these are distinguished by the use of either DCACHE or ICACHE in the macro names. In the following descriptions, XCACHE is also used to stand for either of these. Where there are issues specific to a particular cache, this will be explained in the text.

There might be restrictions on the use of some of the macros which it is the user"s responsibility to comply with. Such restrictions are documented in the `hal_cache.h` file.

Note that destructive cache macros should be used with caution. Preceding a cache invalidation with a cache synchronization is not safe in itself since an interrupt may happen after the synchronization but before the invalidation. This might cause the state of dirty data lines created during the interrupt to be lost.

Depending on the architecture"s capabilities, it may be possible to temporarily disable the cache while doing the synchronization and invalidation which solves the problem (no new data would be cached during an interrupt). Otherwise it is necessary to disable interrupts while manipulating the cache which may take a long time.

### Cache dimensions

    HAL_XCACHE_SIZE
    HAL_XCACHE_LINE_SIZE
    HAL_XCACHE_WAYS
    HAL_XCACHE_SETS

These macros define the size and dimensions of the Instruction and Data caches.

HAL_XCACHE_SIZE

  gives the total size of the cache in bytes.

HAL_XCACHE_LINE_SIZE

  gives the cache line size in bytes.

HAL_XCACHE_WAYS

  gives the number of ways in each set and defines its level of associativity. This would be 1 for a direct mapped cache.

HAL_XCACHE_SETS

  gives the number of sets in the cache, and is derived from the previous values.

### Global cache control

    HAL_XCACHE_ENABLE()
    HAL_XCACHE_DISABLE()
    HAL_XCACHE_INVALIDATE_ALL()
    HAL_XCACHE_SYNC()
    HAL_XCACHE_BURST_SIZE( size )
    HAL_DCACHE_WRITE_MODE( mode )
    HAL_XCACHE_LOCK( base, size )
    HAL_XCACHE_UNLOCK( base, size )
    HAL_XCACHE_UNLOCK_ALL()

These macros affect the state of the entire cache, or a large part of it.

HAL_XCACHE_ENABLE() and HAL_XCACHE_DISABLE()

  enable and disable the cache.

HAL_XCACHE_INVALIDATE_ALL()

  causes the entire contents of the cache to be invalidated.

HAL_XCACHE_SYNC()

  causes the contents of the cache to be brought into synchronization with the contents of memory. In some implementations this may be equivalent to HAL_XCACHE_INVALIDATE_ALL().

HAL_XCACHE_BURST_SIZE()

  allows the size of cache to/from memory bursts to be controlled. This macro will only be defined if this functionality is available.

HAL_DCACHE_WRITE_MODE()

  controls the way in which data cache lines are written back to memory. There will be definitions for the possible modes. Typical definitions are HAL_DCACHE_WRITEBACK_MODE and HAL_DCACHE_WRITETHRU_MODE. This macro will only be defined if this functionality is available.

HAL_XCACHE_LOCK()

  causes data to be locked into the cache. The base and size arguments define the memory region that will be locked into the cache. It is architecture dependent whether more than one locked region is allowed at any one time, and whether this operation causes the cache to cease acting as a cache for addresses outside the region during the duration of the lock. This macro will only be defined if this functionality is available.

HAL_XCACHE_UNLOCK()

  cancels the locking of the memory region given. This should normally correspond to a region supplied in a matching lock call. This macro will only be defined if this functionality is available.

HAL_XCACHE_UNLOCK_ALL()

  cancels all existing locked memory regions. This may be required as part of the cache initialization on some architectures. This macro will only be defined if this functionality is available.

### Cache line control

    HAL_DCACHE_ALLOCATE( base , size )
    HAL_DCACHE_FLUSH( base , size )
    HAL_XCACHE_INVALIDATE( base , size )
    HAL_DCACHE_STORE( base , size )
    HAL_DCACHE_READ_HINT( base , size )
    HAL_DCACHE_WRITE_HINT( base , size )
    HAL_DCACHE_ZERO( base , size )

All of these macros apply a cache operation to all cache lines that match the memory address region defined by the base and size arguments. These macros will only be defined if the described functionality is available. Also, it is not guaranteed that the cache function will only be applied to just the described regions, in some architectures it may be applied to the whole cache.

HAL_DCACHE_ALLOCATE()

  allocates lines in the cache for the given region without reading their contents from memory, hence the contents of the lines is undefined. This is useful for preallocating lines which are to be completely overwritten, for example in a block copy operation.

HAL_DCACHE_FLUSH()

  invalidates all cache lines in the region after writing any dirty lines to memory.

HAL_XCACHE_INVALIDATE()

  invalidates all cache lines in the region. Any dirty lines are invalidated without being written to memory.

HAL_DCACHE_STORE()

  writes all dirty lines in the region to memory, but does not invalidate any lines.

HAL_DCACHE_READ_HINT()

  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 read into the cache.

HAL_DCACHE_WRITE_HINT()

  hints to the cache that the region is going to be written to in the near future. This may have the identical behavior to HAL_DCACHE_READ_HINT().

HAL_DCACHE_ZERO()

  allocates and zeroes lines in the cache for the given region without reading memory. This is useful if a large area of memory is to be cleared.

## `hal/ARCH/arch/v1_2_1/src/ARCH.ld`

This is the architecture specific linker script file. It defines the section types required for the architecture. During preprocessing, the memory layout specified for the chosen platform and startup type is included, defining region, alignment and location parameters for the sections.

## `hal/ARCH/arch/v1_2_1/src/vectors.S`

This file contains code to deal with exception and interrupt vectors. Since the reset entry point is usually implemented as one of these it also deals with system startup.

The exact implementation of this code is under the control of the HAL implementer. So long as it interacts correctly with the macros defined in `hal_intr.h` it may take any form. However, all current implementation follow the same pattern, and there should be a very good reason to break with this. The rest of this section describes how the standard HAL implementation operates.

This file usually contains the following sections of code:

- Startup and initialization code.

- Exception delivery.

- Default handling of synchronous exception.

- Default handling of interrupts.

### HAL startup

Execution normally begins at the reset vector with the machine in a minimal startup state.

The following is a list of the jobs that need to be done in approximately the order in which they should be accomplished. Many of these will not be needed in some configurations.

- Initialize various CPU status registers. Most importantly, the CPU interrupt mask should be set to disable interrupts.

- Set up any CPU memory controller to access RAM, ROM and I/O devices correctly. Until this is done it may not be possible to access RAM.

- Enable the cache, if it is to be used. This may require enabling the CPU"s memory management system since that is often the only way of controlling the cacheability of memory. If this is necessary, a direct one-to-one mapping between physical and virtual memory is most desirable.

- Set up the stack pointer, this allows subsequent initialization code to make procedure calls.

- Initialize any global pointer register needed for access to globally defined variables. This allows subsequent initialization code to access global variables.

- Perform any platform specific initialization. This is best accomplished by calling an initialization routine in `PLATFORM.S` (see the section called `hal/ARCH/PLATFORM/v1_2_1/src/PLATFORM.S`).

- If the system is starting from ROM, copy the ROM template of the `.data` section out to its correct position in RAM. (See the section called `hal/ARCH/arch/v1_2_1/src/ARCH.ld`).

- Zero the `BSS` section.

- Create a suitable C call stack frame.

- Call `cyg_hal_invoke_constructors()` to run any static constructors.

- Call `cyg_start()`. If `cyg_start()` returns, drop into an infinite loop.

### Vectors and VSRs

The CPU delivers all exceptions whether synchronous or interrupts to a set of vectors. Depending on the architecture, these may be implemented in a number of different ways. Examples of existing mechanisms are:

PowerPC

  Exceptions are vectored to locations 256 bytes apart starting at either zero or `0xFFF00000`. There are 16 such vectors defined by the architecture and extra vectors may be defined by specific implementations.

MIPS

  All exceptions are vectored to a single address and software is responsible for reading the exception code from a CPU register to discover its true source.

MN10300

  External interrupts are vectored to an address stored in one of seven interrupt vector registers. These only supply the lower 16 bits of the address, the upper 16 bits are fixed to `0x4000XXXX`. Hence the service routine is constrained to the 64k range starting at `0x40000000`.

Pentium

  Exceptions are delivered via an Interrupt Descriptor Table (IDT) which is essentially an indirection table indexed by exception type. The IDT may be placed anywhere in memory. In PC hardware the interrupt controller can be programmed to deliver the external interrupts to a block of 16 vectors at any offset in the IDT.

680X0

  Exceptions are delivered via an indirection table described by a CPU base register (for X > 0). External interrupts are either delivered via a set of level-specific vectors defined by the architecture, or a vector number may be supplied by the device in which case another entry in the table may be used.

The model adopted by the HAL is that VSRs should be easily replaceable with a pointer to an alternative routine. Of the above architectures, only the Pentium and 680X0 allow this directly in the hardware. In the other three, extra software is required. The code attached directly to the vector is a short trampoline that indirects by way of a HAL supplied VSR table to the true VSR. In the PowerPC and MN10300 the table offset is implicit in the vector routine called, for the MIPS the code reads the `cause` register and indirects through the appropriate table entry.

## Default exception handling

Most synchronous exception vectors will point to a default exception VSR which is responsible for handling all exceptions in a generic manner.

Since most exceptions handled by this VSR are errors (or breakpoints when a program is being debugged), its default behavior should be to save the entire machine state, disable interrupts, and invoke the debugger"s entry point, passing it a pointer to the saved state.

If the debugger returns then the saved state is restored and the interrupted code resumed. Since the debugger may adjust the saved state while it runs a little care must be taken to restore the state correctly.

## Default interrupt handling

Most external interrupt vectors will point to a default interrupt VSR which decode the actual interrupt being delivered and invokes the appropriate ISR.

The default interrupt VSR has a number of responsibilities if it is going to interact with the Kernel cleanly and allow interrupts to cause thread preemption.

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 an interrupt object pointer needed by the kernel. It is implementation defined whether these are stored in a single table of triples, or in three separate tables.

The VSR should follow the following approximate plan:

- Save the CPU state. In non-debug configurations, it may be possible to get away with saving less than the entire machine state.

- Increment the kernel scheduler lock. This is a static member of the Cyg_Scheduler class. It may be necessary to look at a objdump or assembler listing of `sched.cxx` to discover its mangled label.

- (Optional) Switch to an interrupt stack if not already running on it. This allows nested interrupts to be delivered without needing every thread to have a stack large enough to take the maximum possible nesting. It is implementation defined how to detect whether this is a nested interrupt.

- (Optional) Re-enable interrupts to permit nesting.

- Decode the actual external interrupt being delivered from the interrupt controller. This will yield the ISR vector number.

- Using the ISR vector number as an index, retrieve the ISR pointer and its data pointer from the ISR vector table.

- Construct a C call stack frame.

- Call the ISR, passing the vector number and data pointer. The vector number and a pointer to the saved state should be preserved across this call, preferably by storing them in registers that are defined to be callee-saved by the calling conventions.

- If this is an un-nested interrupt and a separate interrupt stack is being used, switch back to the interrupted thread"s own stack.

- (Optional) If interrupts were not enabled above, enable them here since the `interrupt_end()` function must be called with interrupts enabled.

- Use the saved ISR vector number to get the interrupt object pointer from the ISR vector table.

- Call `interrupt_end()` passing it the return value from the ISR, the interrupt object pointer and a pointer to the saved CPU state. This function is implemented by the Kernel and is responsible for finishing off the interrupt handling. Specifically, it may post a DSR depending on the ISR return value, and will decrement the scheduler lock. If the lock is zeroed by this then it may result in a thread context switch.

- When `interrupt_end()` returns, restore the machine state and resume execution of the interrupted thread. Depending on the architecture, it may be necessary to disable interrupts again for part of this.

The detailed order of these steps may vary slightly depending on the architecture, in particular where interrupts are enabled and disabled.

## `hal/ARCH/arch/v1_2_1/src/hal_misc.c`

This file contains any miscellaneous functions that are reference by the HAL. Typical functions that might go here are C implementations of the least- and most- significant bit index routines, constructor calling functions such as `cyg_hal_invoke_constructors()` and support routines for the exception and interrupt vector handling.

## `hal/ARCH/PLATFORM/v1_2_1/include/pkgconf/STARTUP.mlt`

For each startup type (STARTUP) the memory layout of the sections is defined. This information may be edited using the Configuration Tool only.

## `hal/ARCH/PLATFORM/v1_2_1/include/pkgconf/STARTUP.ldi`

For each startup type (STARTUP) the memory layout of the sections is exported by the Configuration Tool as a linker script fragment suitable for inclusion within the architecture-specific linker script file during preprocessing. The linker script fragment to be included is specified by the CYGHWR_MEMORY_LAYOUT_LDI macro in the `system.h` header file. The linker script fragments will be overwritten by the Configuration Tool and should only edited manually where the Configuration Tool is not in use.

## `hal/ARCH/PLATFORM/v1_2_1/include/hal_diag.h`

During early development it is useful to have the ability to output messages to some default destination. This may be a memory buffer, a simulator supported output channel, a ROM emulator virtual UART or a serial line. This file defines set of macros that provide simple, polled output for this purpose.

`HAL_DIAG_INIT()` performs any initialization required on the device being used to generate diagnostic output. This may include setting baud rate, and stop, parity and character bits.

`HAL_DIAG_WRITE_CHAR(c)` writes the character supplied to the diagnostic output device.

These macros may either implement the required functionality directly, or may call functions elsewhere in the HAL to do it. In the latter case these should be in the file `hal/ARCH/PLATFORM/v1_2_1/src/hal_diag.c`.

## `hal/ARCH/PLATFORM/v1_2_1/src/PLATFORM.S`

This is a platform specific assembly code file. Its main purpose is to contain any platform specific startup code called from `vectors.S`.

## `hal/ARCH/PLATFORM/v1_2_1/src/context.S`

If present, this is an assembly code file that contains the code to support thread contexts. The routines to switch between various contexts, as well as initialize a thread context may be present in this file.

## `hal/ARCH/PLATFORM/v1_2_1/src/hal_diag.c`

If present, this file contains the implementation of the HAL diagnostic support routines.

Prev | Home | Next
General principles | Up | Future developments