doc: Add section on floating point services to Kernel Primer
Change-Id: Ic96385595740796e6bb28425cacd05a1285a89bb Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
This commit is contained in:
parent
8cbb09ec37
commit
a891c045a7
2 changed files with 183 additions and 0 deletions
|
@ -12,3 +12,4 @@ microkernel applications and nanokernel applications.
|
|||
common_contexts.rst
|
||||
common_kernel_clocks.rst
|
||||
common_atomic.rst
|
||||
common_float.rst
|
||||
|
|
182
doc/kernel/common/common_float.rst
Normal file
182
doc/kernel/common/common_float.rst
Normal file
|
@ -0,0 +1,182 @@
|
|||
.. _float_services:
|
||||
|
||||
Floating Point Services
|
||||
#######################
|
||||
|
||||
.. note::
|
||||
Floating point services are currently available only for platforms
|
||||
based on the Intel x86 architecture.
|
||||
|
||||
Concepts
|
||||
********
|
||||
|
||||
The kernel allows an application's tasks and fibers to use floating point
|
||||
registers on platform configurations that support these registers.
|
||||
Threads that use the x87 FPU/MMX registers are known as "FPU users",
|
||||
while threads that use SSE registers are known as "SSE users".
|
||||
|
||||
.. note::
|
||||
The kernel does not support the use of floating point registers by ISRs.
|
||||
|
||||
The kernel can be configured to provide only the floating point services
|
||||
required by an application. Three modes of operation are supported,
|
||||
which are described below. In addition, the kernel's support for the SSE
|
||||
registers can be included or omitted, as desired.
|
||||
|
||||
No FP registers mode
|
||||
====================
|
||||
|
||||
This mode is used when the application has no tasks or fibers that use
|
||||
floating point registers. It is the kernel's default floating point services
|
||||
mode.
|
||||
|
||||
If a task or fiber uses any floating point register,
|
||||
the kernel generates a fatal error condition and aborts the thread.
|
||||
|
||||
Unshared FP registers mode
|
||||
==========================
|
||||
|
||||
This mode is used when the application has only a single task or fiber
|
||||
that uses floating point registers.
|
||||
|
||||
The kernel initializes the floating point registers so they can be used
|
||||
by any task or fiber. The floating point registers are left unchanged
|
||||
whenever a context switch occurs.
|
||||
|
||||
.. note::
|
||||
Incorrect operation may result if two or more tasks or fibers use
|
||||
floating point registers, as the kernel does not attempt to detect
|
||||
(or prevent) multiple threads from using these registers.
|
||||
|
||||
Shared FP registers mode
|
||||
========================
|
||||
|
||||
This mode is used when the application has two or more tasks or fibers
|
||||
that use floating point registers.
|
||||
|
||||
The kernel initializes the floating point registers so they can be used
|
||||
by any task or fiber, then saves and restores these registers during
|
||||
context switches to ensure the computations performed by each FPU user
|
||||
or SSE user are not impacted by the computations performed by the other users.
|
||||
A "lazy save" algorithm is used during context switching which updates the
|
||||
floating point registers only when it is absolutely necessary---for example,
|
||||
the registers are *not* saved when switching from an FPU user to a thread
|
||||
that does not use the floating point registers, and then switching back
|
||||
to the original FPU user.
|
||||
|
||||
Every task that uses the floating point registers must provide stack space
|
||||
where the kernel can save the registers during context switches. An FPU user
|
||||
must provide 108 bytes of added stack space, above and beyond its normal
|
||||
requirements; an SSE user must provide 464 bytes of added stack space.
|
||||
|
||||
.. note::
|
||||
A task that does *not* use the floating point registers does not need
|
||||
to provide any added stack space. A fiber does *not* need to provide any
|
||||
added stack space, regardless of whether or not it uses the floating
|
||||
point registers.
|
||||
|
||||
The kernel automatically detects that a given task or fiber is using
|
||||
the floating point registers the first time the thread accesses them.
|
||||
The thread is tagged as an SSE user if the kernel has been configured
|
||||
to support the SSE registers, or as an FPU user if the SSE registers are
|
||||
not supported. If this would result in a thread that is an FPU user being
|
||||
tagged as an SSE user, or if the application wants to avoid the exception
|
||||
handling overhead involved in auto-tagging threads, it is possible to
|
||||
pre-tag a thread using one of the techniques listed below.
|
||||
|
||||
* A task or fiber can tag itself as an FPU user or SSE user by calling
|
||||
:c:func:`task_float_enable()` or :c:func:`fiber_float_enable()`
|
||||
once it has started executing.
|
||||
|
||||
* A fiber can be tagged as an FPU user or SSE user by its creator
|
||||
when the fiber is started.
|
||||
|
||||
* A microkernel task can be tagged as an FPU user or SSE user by adding it
|
||||
to the :c:macro:`FPU` task group or the :c:macro:`SSE` task group
|
||||
when the task is defined.
|
||||
|
||||
.. note::
|
||||
Adding the task to the :c:macro:`FPU` or :c:macro:`SSE` task groups
|
||||
by calling :c:func:`task_group_join()` does *not* tag the task
|
||||
as an FPU user or SSE user.
|
||||
|
||||
If a task or fiber uses the floating point registers infrequently
|
||||
it can call :c:func:`task_float_disable()` or :c:func:`fiber_float_disable()`
|
||||
to remove its tagging as an FPU user or SSE user. This eliminates the need
|
||||
for the kernel to take steps to preserve the contents of the floating point
|
||||
registers during context switches when there is no need to do so.
|
||||
When the thread again needs to use the floating point registers it can re-tag
|
||||
itself as an FPU user or SSE user using one of the techniques listed above.
|
||||
|
||||
|
||||
Purpose
|
||||
*******
|
||||
|
||||
Use the kernel floating point services when an application needs to
|
||||
perform floating point operations.
|
||||
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Configuring Floating Point Services
|
||||
===================================
|
||||
|
||||
To configure unshared FP registers mode, enable the :option:`FLOAT`
|
||||
configuration option and leave the :option:`FP_SHARING` configuration option
|
||||
disabled.
|
||||
|
||||
To configure shared FP registers mode, enable both the :option:`FLOAT`
|
||||
configuration option and the :option:`FP_SHARING` configuration option.
|
||||
Also, ensure that any task that uses the floating point registers has
|
||||
sufficient added stack space for saving floating point register values
|
||||
during context switches, as described above.
|
||||
|
||||
Use the :option:`SSE` configuration option to enable support for
|
||||
SSEx instructions.
|
||||
|
||||
|
||||
Example: Performing Floating Point Arithmetic
|
||||
=============================================
|
||||
This code shows how a routine can use floating point arithmetic to avoid
|
||||
overflow issues when computing the average of a series of integer values.
|
||||
Note that no special coding is required if the kernel is properly configured.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int average(int *values, int num_values)
|
||||
{
|
||||
double sum;
|
||||
int i;
|
||||
|
||||
sum = 0.0;
|
||||
|
||||
for (i = 0; i < num_values; i++) {
|
||||
sum += *values;
|
||||
values++;
|
||||
}
|
||||
|
||||
return (int)((sum / num_values) + 0.5);
|
||||
}
|
||||
|
||||
APIs
|
||||
****
|
||||
|
||||
The following floating point services APIs are provided by
|
||||
:file:`microkernel.h` and by :file:`nanokernel.h`:
|
||||
|
||||
:c:func:`fiber_float_enable()`
|
||||
Tells the kernel that the specified task or fiber is now an FPU user
|
||||
or SSE user.
|
||||
|
||||
:c:func:`task_float_enable()`
|
||||
Tells the kernel that the specified task or fiber is now an FPU user
|
||||
or SSE user.
|
||||
|
||||
:c:func:`fiber_float_disable()`
|
||||
Tells the kernel that the specified task or fiber is no longer an FPU user
|
||||
or SSE user.
|
||||
|
||||
:c:func:`task_float_disable()`
|
||||
Tells the kernel that the specified task or fiber is no longer an FPU user
|
||||
or SSE user.
|
Loading…
Add table
Add a link
Reference in a new issue