1 //*****************************************************************************
2 //
3 // fpu.c - Routines for manipulating the floating-point unit in the Cortex-M
4 //         processor.
5 //
6 // Copyright (c) 2011-2012 Texas Instruments Incorporated.  All rights reserved.
7 // Software License Agreement
8 //
9 //   Redistribution and use in source and binary forms, with or without
10 //   modification, are permitted provided that the following conditions
11 //   are met:
12 //
13 //   Redistributions of source code must retain the above copyright
14 //   notice, this list of conditions and the following disclaimer.
15 //
16 //   Redistributions in binary form must reproduce the above copyright
17 //   notice, this list of conditions and the following disclaimer in the
18 //   documentation and/or other materials provided with the
19 //   distribution.
20 //
21 //   Neither the name of Texas Instruments Incorporated nor the names of
22 //   its contributors may be used to endorse or promote products derived
23 //   from this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // This is part of revision 9453 of the Stellaris Peripheral Driver Library.
38 //
39 //*****************************************************************************
40 
41 //*****************************************************************************
42 //
43 //! \addtogroup fpu_api
44 //! @{
45 //
46 //*****************************************************************************
47 
48 #include "inc/hw_nvic.h"
49 #include "inc/hw_types.h"
50 #include "driverlib/fpu.h"
51 
52 //*****************************************************************************
53 //
54 //! Enables the floating-point unit.
55 //!
56 //! This function enables the floating-point unit, allowing the floating-point
57 //! instructions to be executed.  This function must be called prior to
58 //! performing any hardware floating-point operations; failure to do so results
59 //! in a NOCP usage fault.
60 //!
61 //! \return None.
62 //
63 //*****************************************************************************
64 void
FPUEnable(void)65 FPUEnable(void)
66 {
67     //
68     // Enable the coprocessors used by the floating-point unit.
69     //
70     HWREG(NVIC_CPAC) = ((HWREG(NVIC_CPAC) &
71                          ~(NVIC_CPAC_CP10_M | NVIC_CPAC_CP11_M)) |
72                         NVIC_CPAC_CP10_FULL | NVIC_CPAC_CP11_FULL);
73 }
74 
75 //*****************************************************************************
76 //
77 //! Disables the floating-point unit.
78 //!
79 //! This function disables the floating-point unit, preventing floating-point
80 //! instructions from executing (generating a NOCP usage fault instead).
81 //!
82 //! \return None.
83 //
84 //*****************************************************************************
85 void
FPUDisable(void)86 FPUDisable(void)
87 {
88     //
89     // Disable the coprocessors used by the floating-point unit.
90     //
91     HWREG(NVIC_CPAC) = ((HWREG(NVIC_CPAC) &
92                          ~(NVIC_CPAC_CP10_M | NVIC_CPAC_CP11_M)) |
93                         NVIC_CPAC_CP10_DIS | NVIC_CPAC_CP11_DIS);
94 }
95 
96 //*****************************************************************************
97 //
98 //! Enables the stacking of floating-point registers.
99 //!
100 //! This function enables the stacking of floating-point registers s0-s15 when
101 //! an interrupt is handled.  When enabled, space is reserved on the stack for
102 //! the floating-point context and the floating-point state is saved into this
103 //! stack space.  Upon return from the interrupt, the floating-point context is
104 //! restored.
105 //!
106 //! If the floating-point registers are not stacked, floating-point
107 //! instructions cannot be safely executed in an interrupt handler because the
108 //! values of s0-s15 are not likely to be preserved for the interrupted code.
109 //! On the other hand, stacking the floating-point registers increases the
110 //! stacking operation from 8 words to 26 words, also increasing the interrupt
111 //! response latency.
112 //!
113 //! \return None.
114 //
115 //*****************************************************************************
116 void
FPUStackingEnable(void)117 FPUStackingEnable(void)
118 {
119     //
120     // Enable automatic state preservation for the floating-point unit, and
121     // disable lazy state preservation (meaning that the floating-point state
122     // is always stacked when floating-point instructions are used).
123     //
124     HWREG(NVIC_FPCC) = (HWREG(NVIC_FPCC) & ~NVIC_FPCC_LSPEN) | NVIC_FPCC_ASPEN;
125 }
126 
127 //*****************************************************************************
128 //
129 //! Enables the lazy stacking of floating-point registers.
130 //!
131 //! This function enables the lazy stacking of floating-point registers s0-s15
132 //! when an interrupt is handled.  When lazy stacking is enabled, space is
133 //! reserved on the stack for the floating-point context, but the
134 //! floating-point state is not saved.  If a floating-point instruction is
135 //! executed from within the interrupt context, the floating-point context is
136 //! first saved into the space reserved on the stack.  On completion of the
137 //! interrupt handler, the floating-point context is only restored if it was
138 //! saved (as the result of executing a floating-point instruction).
139 //!
140 //! This method provides a compromise between fast interrupt response (because
141 //! the floating-point state is not saved on interrupt entry) and the ability
142 //! to use floating-point in interrupt handlers (because the floating-point
143 //! state is saved if floating-point instructions are used).
144 //!
145 //! \return None.
146 //
147 //*****************************************************************************
148 void
FPULazyStackingEnable(void)149 FPULazyStackingEnable(void)
150 {
151     //
152     // Enable automatic and lazy state preservation for the floating-point
153     // unit.
154     //
155     HWREG(NVIC_FPCC) |= NVIC_FPCC_ASPEN | NVIC_FPCC_LSPEN;
156 }
157 
158 //*****************************************************************************
159 //
160 //! Disables the stacking of floating-point registers.
161 //!
162 //! This function disables the stacking of floating-point registers s0-s15 when
163 //! an interrupt is handled.  When floating-point context stacking is disabled,
164 //! floating-point operations performed in an interrupt handler destroy the
165 //! floating-point context of the main thread of execution.
166 //!
167 //! \return None.
168 //
169 //*****************************************************************************
170 void
FPUStackingDisable(void)171 FPUStackingDisable(void)
172 {
173     //
174     // Disable automatic and lazy state preservation for the floating-point
175     // unit.
176     //
177     HWREG(NVIC_FPCC) &= ~(NVIC_FPCC_ASPEN | NVIC_FPCC_LSPEN);
178 }
179 
180 //*****************************************************************************
181 //
182 //! Selects the format of half-precision floating-point values.
183 //!
184 //! \param ulMode is the format for half-precision floating-point value, which
185 //! is either \b FPU_HALF_IEEE or \b FPU_HALF_ALTERNATE.
186 //!
187 //! This function selects between the IEEE half-precision floating-point
188 //! representation and the Cortex-M processor alternative representation.  The
189 //! alternative representation has a larger range but does not have a way to
190 //! encode infinity (positive or negative) or NaN (quiet or signaling).  The
191 //! default setting is the IEEE format.
192 //!
193 //! \note Unless this function is called prior to executing any floating-point
194 //! instructions, the default mode is used.
195 //!
196 //! \return None.
197 //
198 //*****************************************************************************
199 void
FPUHalfPrecisionModeSet(unsigned long ulMode)200 FPUHalfPrecisionModeSet(unsigned long ulMode)
201 {
202     //
203     // Set the half-precision floating-point format.
204     //
205     HWREG(NVIC_FPDSC) = (HWREG(NVIC_FPDSC) & ~(NVIC_FPDSC_AHP)) | ulMode;
206 }
207 
208 //*****************************************************************************
209 //
210 //! Selects the NaN mode.
211 //!
212 //! \param ulMode is the mode for NaN results; which is either
213 //! \b FPU_NAN_PROPAGATE or \b FPU_NAN_DEFAULT.
214 //!
215 //! This function selects the handling of NaN results during floating-point
216 //! computations.  NaNs can either propagate (the default), or they can return
217 //! the default NaN.
218 //!
219 //! \note Unless this function is called prior to executing any floating-point
220 //! instructions, the default mode is used.
221 //!
222 //! \return None.
223 //
224 //*****************************************************************************
225 void
FPUNaNModeSet(unsigned long ulMode)226 FPUNaNModeSet(unsigned long ulMode)
227 {
228     //
229     // Set the NaN mode.
230     //
231     HWREG(NVIC_FPDSC) = (HWREG(NVIC_FPDSC) & ~(NVIC_FPDSC_DN)) | ulMode;
232 }
233 
234 //*****************************************************************************
235 //
236 //! Selects the flush-to-zero mode.
237 //!
238 //! \param ulMode is the flush-to-zero mode; which is either
239 //! \b FPU_FLUSH_TO_ZERO_DIS or \b FPU_FLUSH_TO_ZERO_EN.
240 //!
241 //! This function enables or disables the flush-to-zero mode of the
242 //! floating-point unit.  When disabled (the default), the floating-point unit
243 //! is fully IEEE compliant.  When enabled, values close to zero are treated as
244 //! zero, greatly improving the execution speed at the expense of some accuracy
245 //! (as well as IEEE compliance).
246 //!
247 //! \note Unless this function is called prior to executing any floating-point
248 //! instructions, the default mode is used.
249 //!
250 //! \return None.
251 //
252 //*****************************************************************************
253 void
FPUFlushToZeroModeSet(unsigned long ulMode)254 FPUFlushToZeroModeSet(unsigned long ulMode)
255 {
256     //
257     // Set the flush-to-zero mode.
258     //
259     HWREG(NVIC_FPDSC) = (HWREG(NVIC_FPDSC) & ~(NVIC_FPDSC_FZ)) | ulMode;
260 }
261 
262 //*****************************************************************************
263 //
264 //! Selects the rounding mode for floating-point results.
265 //!
266 //! \param ulMode is the rounding mode.
267 //!
268 //! This function selects the rounding mode for floating-point results.  After
269 //! a floating-point operation, the result is rounded toward the specified
270 //! value.  The default mode is \b FPU_ROUND_NEAREST.
271 //!
272 //! The following rounding modes are available (as specified by \e ulMode):
273 //!
274 //! - \b FPU_ROUND_NEAREST - round toward the nearest value
275 //! - \b FPU_ROUND_POS_INF - round toward positive infinity
276 //! - \b FPU_ROUND_NEG_INF - round toward negative infinity
277 //! - \b FPU_ROUND_ZERO - round toward zero
278 //!
279 //! \note Unless this function is called prior to executing any floating-point
280 //! instructions, the default mode is used.
281 //!
282 //! \return None.
283 //
284 //*****************************************************************************
285 void
FPURoundingModeSet(unsigned long ulMode)286 FPURoundingModeSet(unsigned long ulMode)
287 {
288     //
289     // Set the rounding mode.
290     //
291     HWREG(NVIC_FPDSC) = (HWREG(NVIC_FPDSC) & ~(NVIC_FPDSC_RMODE_M)) | ulMode;
292 }
293 
294 //*****************************************************************************
295 //
296 // Close the Doxygen group.
297 //! @}
298 //
299 //*****************************************************************************
300