FP Contexts
-----------
Multiple-context versions of the floating point system (version 4.12 or later
of FPEmulator, indicated by an "M" suffix in the help string) allow rapid
switching between processes using floating point, preserving the complete
state of the system, including any pending asynchronous exceptions. A
floating point context is an opaque block of memory used to hold the state of
the system - an active context must be in an unpaged area of memory, such as
the RMA. SWIs are provided to switch between contexts, and the floating point
system provides a single default context which is activated when the module
is loaded.

In all calls that take or return a context pointer, -1 is used to represent
the default context. 0 indicates no context - if no context is active, then
floating point instructions will generate undefined instruction exceptions.

The contents of a floating point context should be regarded as a "black box":
software outside the floating point system itself should neither assume that
it knows how to interpret them, nor alter them directly. However, the system
does provide some facilities to allow inspection and modification of a
floating point context.

Floating point context switching may be of use for performing floating point
during interrupts or callbacks, or as part of threading schemes. But note
that use of floating point instructions from SVC mode in versions of RISC OS
prior to RISC OS 4 is only possible under the following constraints:

    * The instruction must not use R13 or R14 in any way;
    * R14 must be treated as a scratch register (i.e. it will not
      necessarily be preserved by a floating point instruction);
    * R13 must point correctly to a Full Descending stack with a
      sufficient amount of free space.

This rules out the use of floating point via the C compiler.

It should also be noted that floating point instructions will enable
interrupts if they are handled by the emulator - this is possible even on
systems fitted with hardware floating point.

All the new SWIs corrupt the N Z and C flags.


FPEmulator_DeactivateContext (SWI &40481)
----------------------------

Deactivates the the current floating point context

On entry
    -

On exit
    R0 = current context pointer

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call deactivates the current floating point context, ensuring that
everything about the context is held in memory. It returns the address of the
current floating point context, or zero if the floating point system is in
the completely disabled state described below under FPEmulator_ChangeContext.

You should normally use FPEmulator_ChangeContext in preference to this call.

Note that these calls should be made in pairs, with an
FPEmulator_ActivateContext call following each FPEmulator_DeactivateContext
call, Also, you should not allow any floating point instructions to be
executed between an FPEmulator_DeactivateContext call and the following
FPEmulator_ActivateContext call, since executing a floating point instruction
will re-activate the context and mean that the memory context may no longer
be up-to-date.

Exception: it is legitimate to leave out the call to
FPEmulator_DeactivateContext in the above sequence, but only if the old
context is never going to be used again: it is likely to be in an
inconsistent state if the FPEmulator_DeactivateContext call is omitted.

Related SWIs
    FPEmulator_ActivateContext
    FPEmulator_ChangeContext


FPEmulator_ActivateContext (SWI &40482)
--------------------------

Activates a floating point context

On entry
    R0 = new context pointer (or 0)

On exit
    -

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This is the call that will actually install a suitable undefined instruction
handler, depending on the state of the specified context, what undefined
instruction handlers are available and the hardware present.

This call also actually enables the floating point hardware if it is present
and wanted; in this case, it also loads the context into the hardware.

The argument may also be zero, to indicate that the floating point system
should enter the completely inactive state described below under
FPEmulator_ChangeContext.

You should normally use FPEmulator_ChangeContext in preference to this call.

See the notes under FPEmulator_DeactivateContext relating to restrictions on
this pair of SWIs.

Related SWIs
    FPEmulator_DeactivateContext
    FPEmulator_ChangeContext
    FPEmulator_InitContext


FPEmulator_ChangeContext (SWI &40483)
------------------------

On entry
    R0 = new context pointer (or 0)
On exit
    R0 = old context pointer

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call is the standard way of changing context. A floating point context
pointer is passed to it as an argument. It switches over to using this as the
current context and returns a pointer to the previous floating point context.
It is an atomic equivalent to FPEmulator_DeactivateContext followed by
FPEmulator_ActivateContext.

Either pointer may be zero: this indicates that the floating point system
was/should be in a completely inactive state, with no current floating point
context, its undefined instruction handlers not installed, etc.

Related SWIs
    FPEmulator_DeactivateContext
    FPEmulator_ActivateContext
    FPEmulator_InitContext


FPEmulator_ContextLength (SWI &40484)
------------------------

Returns the size of a floating point context

On entry
    -

On exit
    R0 = size of a floating point context

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call returns the size of a floating point context. It is constant for any
given implementation of the floating point system.

To create your own context, allocate a block of this size in the RMA or some
other unpaged area of memory, then call FPEmulator_InitContext.

Related SWIs
    FPEmulator_InitContext


FPEmulator_InitContext (SWI &40485)
----------------------

Initialises a floating point context

On entry
    R0 = pointer to context

On exit
    -

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call should be made to initialise or re-initialise a floating point
context. It puts the context into a standard starting state, in which:

  All floating point registers contain zeros.

  The FPSR has the OFL, DVZ and IVO exception trap enable bits set. All
  other trap enable, system control and exception flag bits are clear.

This call may also initialise other less obvious context variables. To
initialise a floating point context with other registers and/or FPSR values,
use FPEmulator_InitContext and then switch to the context and load the
desired values with LDF and/or WFS instructions.

Note that this call should not be made on a context that is currently active.
If it is necessary to re-initialise the currently active context, make it no
longer active (by using FPEmulator_ActivateContext or
FPEmulator_ChangeContext'), then re-initialise it, then reactivate it.

Related SWIs
    FPEmulator_ContextLength
    FPEmulator_ActivateContext
    FPEmulator_ChangeContext


FPEmulator_ExceptionDump (SWI &40486)
------------------------

Returns the address of the floating point register dump

On entry
    -

On exit
    R0 = pointer to saved FP register dump

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

When a floating point exception trap is generated, the floating point system
stores the current FP registers in an internal exception dump using
FPEmulator_SaveContext. This call returns a pointer to that register dump.
The Debugger module provides a *ShowFPRegs command to view the dump contents.

On a floating point trap, the integer registers are also stored in the
current exception register dump (OS_ChangeEnvironment 13 - see PRM 1-316),
so they can be viewed using *ShowRegs. Note that floating point registers
are not stored on other exceptions, such as data aborts.

Related SWIs
    None


FPEmulator_Abort (SWI &40487)
----------------

Aborts any incomplete floating point processing

On entry
    R0 = context pointer
    R1 = R12 value associated with context (only relevant if R2 indicates
         a PC value inside the floating point undefined instruction handlers)
    R2 = PC value associated with the context (e.g. the PC value the
         IRQ handler would normally return to)

On exit
    R0 = pointer to frame associated with original non-recursive entry to
         the floating point system if R2 indicated a PC value inside the
         floating point undefined instruction handlers, otherwise zero.

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

It is important in some cases that it should be possible to abort some
partially complete floating point processing.

Some examples:

  * If an invalid address is given to an emulated LDF, STF, LFM or SFM
    instruction, it will result in an address exception or data abort
    occurring on a load or store instruction within the emulator. Had the
    address merely been that of a swapped-out piece of store, a virtual
    memory system could simply swap it in, take other standard remedial
    action and return to the offending instruction. However, since the
    address is actually invalid, this is not possible: typically, what is
    then wanted is that processing of the original LDF, STF, LFM or SFM
    should be abandoned and that some sort of error handler should be
    invoked, with the register values, etc., appropriate to the LDF, STF,
    LFM or SFM being made available to the error handler - not whatever
    values the emulator had in the registers at the time of the internal
    load or store instruction!

  * If some sort of asynchronous signal is raised for a process while it
    is swapped out in the middle of some floating point processing, it may
    be important that you should be able to abandon the partially complete
    floating point processing.

  * If FPEmulator_LoadContext is used to modify the values in a floating
    point context, any floating point processing associated with the old
    values in that context must be aborted. Failure to do this can result
    in all sorts of confusion within the floating point system - e.g.
    exceptions occurring on internal operations which simply shouldn't be
    able to occur and which therefore haven't been catered for.

  * Some types of floating point exception handlers (e.g. Unix signals)
    don't have an IEEE-type trap handler interface, but instead want to
    look at the register values, etc., at the time the floating point
    exception was detected. Again, these shouldn't be the values that the
    floating point system happens to have in the registers when the trap
    handler code is called.

When floating point processing is to be abandoned, three important things
may be required:

  * Any pending exception must be cleared. A pending exception is one that
    has been detected by the hardware, but has not yet caused the
    undefined instruction vector to be entered. Note that if you're doing
    something like FPEmulator_LoadContext, this should be done even if there
    is no obvious floating point processing going on at the time. Also
    note that since there may be a pending exception on an internal
    calculation within the floating point system, it should also be done
    when there *is* some floating point processing going on at the time.

    Finally, note that when a context is deactivated, any pending
    exception for it is stored away without causing the undefined
    instruction vector to be entered at the time: the actual processing
    will occur later. So it is possible for inactive contexts to contain
    pending exceptions, and not just for the currently active context.

  * Any floating point processing that is currently going on should be
    abandoned. This means (a) that a suitable new value for the PC is
    required; (b) that any values put on the stack by the floating point
    system should be discarded; (c) that the values in the floating point
    context concerned should be made consistent with there being no current
    floating point processing.

  * The register values at the time that the exception occurred must be
    made available.

This call cancels any pending exception and aborts any incomplete floating
point processing associated with a given floating point context. It returns
the frame pointer associated with the original non-recursive entry to the
floating point undefined instruction handler, and restores any floating point
registers that have been used for internal calculations. It does *not*
restore contents of this original frame, of other mode registers or of
floating point registers that have been updated as a result of the partial
processing of the original non-recursive floating point instruction.

If register values are required, the stack frame has the following format:

  [R0, #-8]: (on RISC OS 4 or later) Value of SPSR_undef immediately after
             entry to the undefined instruction handler - i.e. value of
             CPSR before entry to the undefined instruction handler;
  [R0, #-4]: (on RISC OS 4 or later) Value of CPSR immediately after entry
             to the undefined instruction handler;
  [R0, #0]:  Value of user R0 immediately after entry to the undefined
             instruction handler;
  [R0, #4]:  Value of user R1 immediately after entry to the undefined
             instruction handler;
  [R0, #8]:  Value of user R2 immediately after entry to the undefined
             instruction handler;
  [R0, #12]: Value of user R3 immediately after entry to the undefined
             instruction handler;
  :          :
  :          :
  :          :
  [R0, #52]: Value of user R13 immediately before entry to the undefined
             instruction handler;
  [R0, #56]: Value of user R14 immediately before entry to the undefined
             instruction handler;
  [R0, #60]: The return link from this undefined instruction call,
             including the PSR bits for 26-bit code; see below for more
             details of this;
  [R0, #64]: This is the location pointed to by the stack pointer (R13_svc
             in RISC OS 3, R13_undef in RISC OS 4 or later) before entry
             to the undefined instruction handler.

Related SWIs
   None


FPEmulator_SaveContext (SWI &40489)
----------------------

Saves the contents of a floating point context

On entry
    R0 = context pointer
    R1 = pointer to 25-word register dump
    R2 = PC value associated with the context

On exit
    R0 = non-zero if there is a pending or incompletely processed
         exception associated with the context, zero if there isn't

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call saves the register and FPSR values held in a floating point
context to a specified 25-word area of memory, in the following format:

  Byte offset   Value
  ------------------------------------------------------------------
       0        FPSR value
       4        F0 value, as an extended precision number
      16        F1 value, as an extended precision number
      28        F2 value, as an extended precision number
      40        F3 value, as an extended precision number
      52        F4 value, as an extended precision number
      64        F5 value, as an extended precision number
      76        F6 value, as an extended precision number
      88        F7 value, as an extended precision number

Note that it does this *without* processing any pending exceptions
associated with the context, or completing the processing of any
exception which is currently being processed. The routine returns a hint
about whether there is a pending or incompletely processed exception
associated with the context: if there is, the values returned may be
rather odd and should *not* be relied upon as an accurate reflection of
reality. For instance, if the FPA has a pending overflow exception, the
destination register of the instruction concerned will often read as
containing a very small number!

This call might be used by a debugger to view the current FP register
contents. The PC value passed in would then be the address at which
execution was interrupted - it is used to detect whether the
floating point system was interrupted in the middle of processing an
exception.

Related SWIs
   FPEmulator_LoadContext


FPEmulator_LoadContext (SWI &40488)
----------------------

Loads a floating point context

On entry
    R0 = context pointer
    R1 = pointer to 25-word area as described under FPEmulator_SaveContext

On exit
    -

Interrupts
    Interrupt status is unaltered
    Fast interrupts are enabled

Processor mode
    Processor is in SVC mode

Re-entrancy
    SWI is re-entrant

This call allows the programmer to load a floating point context with a
specified set of register and FPSR values, destroying any pending or
incompletely processed exception in the process.

This call should almost always be preceded by one to FPEmulator_Abort: you
can create chaos in the floating point system by calling
FPEmulator_LoadContext while there is a pending or incompletely processed
exception.

This call did not work correctly until version 4.17 of the FPEmulator module.

Related SWIs
   FPEmulator_SaveContext
