VxWorks API Reference : OS Libraries
fppArchLib - architecture-dependent floating-point coprocessor support
fppSave( ) - save the floating-point coprocessor context
fppRestore( ) - restore the floating-point coprocessor context
fppProbe( ) - probe for the presence of a floating-point coprocessor
fppTaskRegsGet( ) - get the floating-point registers from a task TCB
fppTaskRegsSet( ) - set the floating-point registers of a task
This library contains architecture-dependent routines to support the floating-point coprocessor. The routines fppSave( ) and fppRestore( ) save and restore all the task floating-point context information. The routine fppProbe( ) checks for the presence of the floating-point coprocessor. The routines fppTaskRegsSet( ) and fppTaskRegsGet( ) inspect and set coprocessor registers on a per-task basis.
With the exception of fppProbe( ), the higher-level facilities in dbgLib and usrLib should be used instead of these routines. For information about architecture-independent access mechanisms, see the manual entry for fppLib.
To activate floating-point support, fppInit( ) must be called before any tasks using the coprocessor are spawned. This is done by the root task, usrRoot( ), in usrConfig.c. See the manual entry for fppLib.
There are two kind of floating-point contexts and set of routines for each kind. One is 108 bytes for older FPU (i80387, i80487, Pentium) and older MMX technology and fppSave( ), fppRestore( ), fppRegsToCtx( ), and fppCtxToRegs( ) are used to save and restore the context, convert to or from the FPPREG_SET. The other is 512 bytes for newer FPU, newer MMX technology and streaming SIMD technology (PentiumII, III, 4) and fppXsave( ), fppXrestore( ), fppXregsToCtx( ), and fppXctxToRegs( ) are used to save and restore the context, convert to or from the FPPREG_SET. Which to use is automatically detected by checking CPUID information in fppArchInit( ). And fppTaskRegsSet( ) and fppTaskRegsGet( ) access the appropriate floating-point context. The bit interrogated for the automatic detection is the "Fast Save and Restore" feature flag.
To activate floating-point support, fppInit( ) must be called before any tasks using the coprocessor are spawned. If INCLUDE_FLOATING_POINT is defined in configAll.h, this is done by the root task, usrRoot( ), in usrConfig.c.
Saving and restoring floating-point registers adds to the context switch time of a task. Therefore, floating-point registers are not saved and restored for every task. Only those tasks spawned with the task option VX_FP_TASK will have floating-point state, MMX technology state, and streaming SIMD state saved and restored.
NOTE: If a task does any floating-point operations, MMX operations, and streaming SIMD operation, it must be spawned with VX_FP_TASK. It is deadly to execute any floating-point operations in a task spawned without VX_FP_TASK option, and very difficult to find. To detect that illegal/unintentional/accidental floating-point operations, a new API and mechanism is added. The mechanism is to enable or disable the FPU by toggling the TS flag in the CR0 in the new task switch hook routine - fppArchSwitchHook( ) - respecting the VX_FP_TASK option. If VX_FP_TASK option is not set in the switching-in task, the FPU is disabled. Thus the device-not-available exception will be raised if that task does any floating-point operations. This mechanism is disabled in the default. To enable, call the enabler - fppArchSwitchHookEnable( ) - with a parameter TRUE(1). A parameter FALSE(0) disables the mechanism.
A task with VX_FP_TASK option saves and restores the FPU and MMX state when performing a context switch. Therefore, the application does not have to save or restore the FPU and MMX state if the FPU and MMX instructions are not mixed within a task. Because the MMX registers are aliased to the FPU registers, care must be taken when making transitions between FPU instructions and MMX instructions to prevent the loss of data in the FPU and MMX registers and to prevent incoherent or unexpected result. When mixing MMX and FPU instructions within a task, follow these guidelines from Intel:
- Keep the code in separate modules, procedures, or routines.
- Do not rely on register contents across transitions between FPU
and MMX code modules.
- When transitioning between MMX code and FPU code, save the MMX
register state (if it will be needed in the future) and execute
an EMMS instruction to empty the MMX state.
- When transitioning between FPU and MMX code, save the FPU state,
if it will be needed in the future.
The XMM registers and the FPU/MMX registers represent separate execution environments, which has certain ramifications when executing SSE, SSE2, MMX and FPU instructions in the same task context:
- Those SSE and SSE2 instruction that operate only on the XMM
registers (such as the packed and scalar floating-point
instructions and the 128-bit SIMD integer instructions) can be
executed in the same instruction stream with 64-bit SIMD integer
or FPU instructions without any restrictions. For example, an
application can perform the majority of its floating-point
computations in the XMM registers, using the packed and scalar
floating-point instructions, and at the same time use the FPU
to perform trigonometric and other transcendental computations.
Likewise, an application can perform packed 64-bit and 128-bit
SIMD integer operations can be executed together without
restrictions.
- Those SSE and SSE2 instructions that operate on MMX registers
(such as the CVTPS2PI, CVTTPS2PI, CVTPI2PS, CVTPD2PI, CVTTPD2PI,
CVTPI2PD, MOVDQ2Q, MOVQ2DQ, PADDQ, and PSUBQ instructions) can
also be executed in the same instruction stream as 64-bit SIMD
integer or FPU instructions, however, here they subject to the
restrictions on the simultaneous use of MMX and FPU instructions,
which mentioned in the previous paragraph.
Floating-point registers are not saved and restored for interrupt service routines connected with intConnect( ). However, if necessary, an interrupt service routine can save and restore floating-point registers by calling routines in fppALib. See the manual entry for intConnect( ) for more information.
There are six FPU exceptions that can send an exception to the CPU. They are controlled by Exception Mask bits of the Control Word register. VxWorks disables them in the default configuration. They are:
- Precision
- Overflow
- Underflow
- Division by zero
- Denormalized operand
- Invalid OperationThe FPU in 486 or later IA32 processors provide two different modes to handle a FPU floating-point exceptions. MSDOS compatibility mode and native mode. The mode of operation is selected with the NE flag of control register CR0. The MSDOS compatibility mode is not supported, because it is old and requires external signal handling. The native mode for handling FPU exceptions is used by setting the NE flag in the control register CR0. In this mode, if the FPU detects an exception condition while executing a floating-point instruction and the exception is unmasked (the mask bit for the exception is cleared), the FPU sets the flag for the exception and the ES flag in the FPU status word. It then invokes the software exception handler through the floating-point-error exception (vector number 16), immediately before execution of any of the following instructions in the processor's instruction stream:
- The next floating-point instruction, unless it is one of the non-waiting
instructions (FNINIT, FNCLEX, FNSTSW, FNSTCW, FNSTENV and FNSAVE).
- The next WAIT/FWAIT instruction.
- The next MMX instruction.If the next floating-point instruction in the instruction stream is a non-waiting instruction, the FPU executes the instruction without invoking the software exception handler. There is a well known FPU exception synchronization problems that occur in the time frame between the moment when the exception is signaled and when it is actually handled. Because of concurrent execution (integer unit and FPU), integer or system instructions can be executed during this time frame. It is thus possible for the source or destination operands for a floating- point instruction that faulted to be overwritten in memory, making it impossible for the exception handler to analyze or recover from the exception. To solve this problem, an exception synchronizing instruction (either a floating-point instruction or a WAIT/FWAIT instruction) can be placed immediately after any floating-point instruction that might present a situation where state information pertaining to a floating-point exception might be lost or corrupted. The preemption could happen at any instruction boundary that maybe right after the faulting instruction, and could result in the task context switch. The task context switch does not perform the FPU context switch always for optimization, and the FPU context switch maybe done in other task context. To make the pending unmasked exceptions to be handled in the task context that it happened, the FPU context switch does not check pending unmasked exceptions, and preserves the exception flags in the status register. It may not be useful to re-execute the faulting instruction, if the faulting floating-point instruction is followed by one or more non-floating-point instructions. The return instruction pointer on the stack (exception stack frame) may not point to the faulting instruction. The faulting instruction pointer is contained in the saved FPU state information. The default exception handler does not replace the return instruction pointer with the faulting instruction pointer. fppCwSet( ) and fppCwGet( ), sets and gets the X86 FPU control word. fppSwGet( ) gets the X86 FPU status word. fppWait( ) checks for pending unmasked FPU exceptions. fppClex( ) clears FPU exception flags after checking unmasked FPU pending exceptions. fppNclex( ) clears FPU exception flags without checking unmasked FPU pending exceptions.
This architecture does not currently support floating-point coprocessors.
fppLib.h
fppLib, intConnect( ),
Gerry Kane and Joe Heinrich: MIPS RISC Architecture Manual
Motorola MC68881/882 Floating-Point Coprocessor User's Manual, Intel 387 DX User's Manual, Intel Architecture Software Developer's Manual, Hitachi SH7750 Hardware Manual,
fppSave( ) - save the floating-point coprocessor context
void fppSave ( FP_CONTEXT * pFpContext /* where to save context */ )
This routine saves the floating-point coprocessor context. The context saved is:
MC680x0:
- registers fpcr, fpsr, and fpiar
- registers f0 - f7
- internal state frame (if NULL, the other registers are not saved.)MIPS:
- register fpcsr
- registers fp0 - fp31SH-4:
- registers fpcsr and fpul
- registers fr0 - fr15
- registers xf0 - xf15x86:
108 byte old context with fsave and frstor instruction
- control word, status word, tag word,
- instruction pointer,
- instruction pointer selector,
- last FP instruction op code,
- data pointer,
- data pointer selector,
- registers st/mm0 - st/mm7 (10 bytes * 8)
512 byte new context with fxsave and fxrstor instruction
- control word, status word, tag word,
- last FP instruction op code,
- instruction pointer,
- instruction pointer selector,
- data pointer,
- data pointer selector,
- registers st/mm0 - st/mm7 (10 bytes * 8)
- registers xmm0 - xmm7 (16 bytes * 8)ARM:
- currently, on this architecture, this routine does nothing.SimSolaris:
- register fsr
- registers f0 - f31SimNT:
- this routine does nothing on Windows simulator. Floating point
registers are saved by Windows.
N/A
fppArchLib, fppRestore( )
fppRestore( ) - restore the floating-point coprocessor context
void fppRestore ( FP_CONTEXT * pFpContext /* where to restore context from */ )
This routine restores the floating-point coprocessor context. The context restored is:
MC680x0:
- registers fpcr, fpsr, and fpiar
- registers f0 - f7
- internal state frame (if NULL, the other registers are not saved.)MIPS:
- register fpcsr
- registers fp0 - fp31SH-4:
- registers fpcsr and fpul
- registers fr0 - fr15
- registers xf0 - xf15x86:
108 byte old context with fsave and frstor instruction
- control word, status word, tag word,
- instruction pointer,
- instruction pointer selector,
- last FP instruction op code,
- data pointer,
- data pointer selector,
- registers st/mm0 - st/mm7 (10 bytes * 8)
512 byte new context with fxsave and fxrstor instruction
- control word, status word, tag word,
- last FP instruction op code,
- instruction pointer,
- instruction pointer selector,
- data pointer,
- data pointer selector,
- registers st/mm0 - st/mm7 (10 bytes * 8)
- registers xmm0 - xmm7 (16 bytes * 8)ARM:
- currently, on this architecture, this routine does nothing.SimSolaris:
- register fsr
- registers f0 - f31SimNT:
- this routine does nothing on Windows simulator.
N/A
fppArchLib, fppSave( )
fppProbe( ) - probe for the presence of a floating-point coprocessor
STATUS fppProbe (void)
This routine determines whether there is a floating-point coprocessor in the system.
The implementation of this routine is architecture-dependent:
- MC680x0, x86, SH-4:
- This routine sets the illegal coprocessor opcode trap vector and executes a coprocessor instruction. If the instruction causes an exception, fppProbe( ) returns ERROR. Note that this routine saves and restores the illegal coprocessor opcode trap vector that was there prior to this call.
The probe is only performed the first time this routine is called. The result is stored in a static and returned on subsequent calls without actually probing.
- MIPS:
- This routine simply reads the R-Series status register and reports the bit that indicates whether coprocessor 1 is usable. This bit must be correctly initialized in the BSP.
- ARM:
- This routine currently returns ERROR to indicate no floating-point coprocessor support.
- SimNT, SimSolaris:
- This routine currently returns OK.
OK, or ERROR if there is no floating-point coprocessor.
fppTaskRegsGet( ) - get the floating-point registers from a task TCB
STATUS fppTaskRegsGet ( int task, /* task to get info about */ FPREG_SET * pFpRegSet /* ptr to floating-point register set */ )
This routine copies a task's floating-point registers and/or status registers to the locations whose pointers are passed as parameters. The floating-point registers are copied into an array containing all the registers.
This routine only works well if task is not the calling task. If a task tries to discover its own registers, the values will be stale (that is, left over from the last task switch).
OK, or ERROR if there is no floating-point support or there is an invalid state.
fppTaskRegsSet( ) - set the floating-point registers of a task
STATUS fppTaskRegsSet ( int task, /* task to set registers for */ FPREG_SET * pFpRegSet /* ptr to floating-point register set */ )
This routine loads the specified values into the TCB of a specified task. The register values are copied from the array at pFpRegSet.
OK, or ERROR if there is no floating-point support or there is an invalid state.